CHT001: ValueTask awaited multiple times
Cause
A ValueTask or ValueTask<T> variable is awaited more than once.
Rule Description
A ValueTask is a struct that can only be consumed once. Unlike Task, which can be safely awaited multiple times, awaiting a ValueTask multiple times leads to undefined behavior. When backed by an IValueTaskSource, the second await may throw InvalidOperationException or return incorrect results.
How to Fix
Option 1: Convert to Task at declaration
If you need to await the result multiple times, convert to Task immediately:
// Before
ValueTask vt = GetValueTask();
await vt;
await vt; // Error
// After
Task t = GetValueTask().AsTask();
await t;
await t; // OK
Option 2: Use Preserve()
Use the Preserve() extension method for safe conversion:
using CryptoHives.Foundation.Threading;
Task t = GetValueTask().Preserve();
await t;
await t; // OK
Option 3: Store the result
If you need the result multiple times, await once and store the result:
// Before
ValueTask<int> vt = GetValueTask();
int a = await vt;
int b = await vt; // Error
// After
int result = await GetValueTask().ConfigureAwait(false);
int a = result;
int b = result; // OK
When to Suppress
Never suppress this diagnostic. Awaiting a ValueTask multiple times is always a bug.
Example
Violating Code
public async Task ProcessAsync()
{
ValueTask vt = DoWorkAsync();
if (someCondition)
{
await vt;
}
await vt; // CHT001: vt already awaited
}
Fixed Code
public async Task ProcessAsync()
{
Task t = DoWorkAsync().AsTask();
if (someCondition)
{
await t;
}
await t; // OK - Task can be awaited multiple times
}