CryptoHives.Foundation.Threading.Analyzers
0.6.21
dotnet add package CryptoHives.Foundation.Threading.Analyzers --version 0.6.21
NuGet\Install-Package CryptoHives.Foundation.Threading.Analyzers -Version 0.6.21
<PackageReference Include="CryptoHives.Foundation.Threading.Analyzers" Version="0.6.21"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="CryptoHives.Foundation.Threading.Analyzers" Version="0.6.21" />
<PackageReference Include="CryptoHives.Foundation.Threading.Analyzers"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add CryptoHives.Foundation.Threading.Analyzers --version 0.6.21
#r "nuget: CryptoHives.Foundation.Threading.Analyzers, 0.6.21"
#:package CryptoHives.Foundation.Threading.Analyzers@0.6.21
#addin nuget:?package=CryptoHives.Foundation.Threading.Analyzers&version=0.6.21
#tool nuget:?package=CryptoHives.Foundation.Threading.Analyzers&version=0.6.21
CryptoHives Open Source Initiative 🐝
An open, community-driven collection of cryptography and performance libraries for the .NET ecosystem, maintained by The Keepers of the CryptoHives.
CryptoHives.Foundation.Threading.Analyzers
Roslyn analyzers that catch common ValueTask misuse at compile time — the kind of subtle bugs, undefined behavior, and performance pitfalls that tend to show up when working with ValueTask and pooled async primitives.
Note: These analyzers are no longer bundled automatically with the CryptoHives.Foundation.Threading package. Install this package separately if you want the analyzers alongside the Threading library.
Installation
dotnet add package CryptoHives.Foundation.Threading.Analyzers
Or as a development-only dependency (no runtime reference):
<PackageReference Include="CryptoHives.Foundation.Threading.Analyzers"
Version="*"
PrivateAssets="all" />
Diagnostic Rules
| ID | Severity | Description |
|---|---|---|
| CHT001 | Error | ValueTask awaited multiple times |
| CHT002 | Warning | ValueTask.GetAwaiter().GetResult() used (blocking) |
| CHT003 | Warning | ValueTask stored in a field |
| CHT004 | Error | ValueTask.AsTask() called multiple times |
| CHT005 | Warning | ValueTask.Result accessed directly |
| CHT006 | Warning | ValueTask passed to a potentially unsafe method |
| CHT007 | Info | AsTask() stored before signaling (causes a performance hit) |
| CHT008 | Warning | ValueTask not awaited or consumed |
| CHT009 | Info | SemaphoreSlim(1, 1) used as an async lock; consider AsyncLock instead |
| CHT010 | Error | ValueTask captured in a lambda/closure |
Anti-Patterns Detected
// CHT001: Multiple await — Error
ValueTask vt = GetValueTask();
await vt;
await vt; // Error: already consumed
// CHT002: Blocking call — Warning
ValueTask vt = GetValueTask();
vt.GetAwaiter().GetResult(); // Warning: undefined behavior
// CHT003: Stored in field — Warning
private ValueTask _task; // Warning: may be consumed multiple times
// CHT004: Multiple AsTask() — Error
ValueTask vt = GetValueTask();
var t1 = vt.AsTask();
var t2 = vt.AsTask(); // Error: already consumed
// CHT005: Direct .Result — Warning
ValueTask<int> vt = GetValueTask();
int result = vt.Result; // Warning: undefined behavior
// CHT006: Passed to unsafe method — Warning
await Task.WhenAll(GetValueTask()); // Warning: use AsTask() or Preserve()
// CHT007: AsTask() before signaling — Info (performance)
Task t = someAsyncLock.LockAsync().AsTask();
// ... other work ...
await t; // Info: storing AsTask() before signal causes 10–100x slowdown
// CHT008: Unconsumed — Warning
GetValueTask(); // Warning: result not awaited or discarded
// CHT009: SemaphoreSlim(1, 1) as async lock — Info
private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1); // Info: consider AsyncLock
Correct Patterns
// Single await — correct
await GetValueTask();
// Store, then single await — correct
ValueTask vt = GetValueTask();
await vt;
// Preserve() for safe multiple consumption
ValueTask preserved = GetValueTask().Preserve();
await preserved;
await preserved; // Safe — Preserve() wraps in a reusable Task
// AsTask() once, reuse the Task
Task t = GetValueTask().AsTask();
await t;
await t; // Task can be awaited multiple times
// Pass to WhenAll via AsTask()
await Task.WhenAll(
GetValueTask().AsTask(),
GetValueTask().AsTask());
// Explicit discard
_ = GetValueTask();
Automatic Code Fixes
Most diagnostics come with a code fix:
| Diagnostic | Available Fixes |
|---|---|
| CHT001 | Convert to AsTask() at declaration; use Preserve() |
| CHT002 | Convert to await; use AsTask() before GetAwaiter().GetResult() |
| CHT003 | Change field type to Task |
| CHT004 | Store AsTask() result in a variable |
| CHT005 | Convert to await; use AsTask().Result |
| CHT007 | Await the ValueTask directly |
| CHT008 | Add await; discard explicitly with _ = |
| CHT009 | Replace SemaphoreSlim(1,1) with AsyncLock |
| CHT010 | Convert to AsTask() at declaration; use Preserve() |
Configuration
Adjust rule severity in .editorconfig:
# Promote CHT007 from info to warning
dotnet_diagnostic.CHT007.severity = warning
# Disable CHT003 entirely
dotnet_diagnostic.CHT003.severity = none
Or suppress inline when it's genuinely intentional:
#pragma warning disable CHT002
valueTask.GetAwaiter().GetResult(); // intentional blocking call
#pragma warning restore CHT002
Documentation
| Resource | Link |
|---|---|
| Full package documentation | cryptohives.github.io/Foundation/packages/threading.analyzers |
| Threading package | cryptohives.github.io/Foundation/packages/threading |
| Source repository | github.com/CryptoHives/Foundation |
Security Policy
If you discover a vulnerability, please don't open a public issue — follow the process on the CryptoHives Security Page instead.
License
MIT — © 2026 The Keepers of the CryptoHives
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.6.21 | 63 | 7/4/2026 |
| 0.5.34-preview | 172 | 6/2/2026 |
| 0.5.21-preview | 119 | 5/2/2026 |
| 0.5.13-preview | 152 | 4/2/2026 |
| 0.4.21-preview | 175 | 3/1/2026 |
| 0.4.11-preview | 116 | 2/14/2026 |
| 0.3.19-preview | 153 | 1/26/2026 |
| 0.2.43-preview | 159 | 1/9/2026 |
| 0.2.33-preview | 465 | 12/9/2025 |
| 0.2.30-preview | 342 | 12/8/2025 |
| 0.2.28-preview | 294 | 12/7/2025 |