October 14, 2026
.NET Simple Lazy Cache
A single-flight caller in C#: one in-flight Lazy per key, removed when the call finishes, with a newer entry left in place.
TL;DR —
SingleFactoryCaller<T>shares one in-flightLazy<Task<T>>per key. When the call finishes, that entry is removed and a later call runs the factory again. A cancellation token from one waiter does not cancel the shared factory.Tis a class.Stack — C#,
netstandard2.0library, xUnit onnet10.0, Coverlet, ReportGenerator, Stryker.NETLinks — Source · Coverage report · The same idea in Java
GetOrAddAsync stores the shared call in a dictionary guarded by a lock. The method awaits that task, and the factory task, with ConfigureAwait(false). A finishing caller removes the dictionary entry only when that entry is still the call it started. A newer entry for the same key stays.
A null or empty key throws ArgumentException. A null factory throws ArgumentNullException. A factory that returns a null task throws InvalidOperationException. A caller can block on the returned task while a synchronization context does not run posted work, and the call still completes. There is no install command and no process to start. A caller uses the library.
The library targets netstandard2.0. The xUnit tests target net10.0 and run with dotnet test. Coverlet writes the Cobertura file, ReportGenerator writes the HTML report, and dotnet-stryker is the local mutation tool. GitHub Actions publishes that HTML report. The Java version of the same caller is Java Simple Lazy Cache.