CHT002: ValueTask blocked with GetAwaiter().GetResult()
Cause
GetAwaiter().GetResult() is called on a ValueTask or ValueTask<T>.
Rule Description
Calling GetAwaiter().GetResult() on a ValueTask is undefined behavior when the ValueTask is backed by an IValueTaskSource. This pattern:
- May cause deadlocks when called on a non-completed
ValueTask - Is undefined behavior for
IValueTaskSource-backedValueTasks - Consumes the
ValueTask, preventing further usage
The pooled primitives in CryptoHives.Foundation.Threading use IValueTaskSource for their ValueTask implementations, making this pattern particularly dangerous.
How to Fix
Option 1: Use await (Recommended)
Convert to async code:
// Before
valueTask.GetAwaiter().GetResult();
// After
await valueTask;
Option 2: Preserve the ValueTask first
If blocking is absolutely necessary (not recommended):
// Before
valueTask.GetAwaiter().GetResult();
// After
valueTask.Preserve().GetAwaiter().GetResult();
Option 3: Convert to Task first
If blocking is absolutely necessary (not recommended):
// Before
valueTask.GetAwaiter().GetResult();
// After
valueTask.AsTask().GetAwaiter().GetResult();
When to Suppress (not recommended)
Only suppress if you can guarantee:
- The
ValueTaskis already completed (IsCompletedSuccessfully == true) - The
ValueTaskis backed by aTask, not anIValueTaskSource
ValueTask vt = GetValueTask();
if (vt.IsCompletedSuccessfully)
{
#pragma warning disable CHT002
vt.GetAwaiter().GetResult(); // Safe only because already completed
#pragma warning restore CHT002
}
Example
Violating Code
public void SyncMethod()
{
ValueTask vt = asyncEvent.WaitAsync();
vt.GetAwaiter().GetResult(); // CHT002
}
Fixed Code
// Option 1: Make method async
public async Task AsyncMethod()
{
await asyncEvent.WaitAsync();
}
// Option 2: Convert to Task first (if blocking is necessary)
public void SyncMethod()
{
asyncEvent.WaitAsync().AsTask().GetAwaiter().GetResult();
}