-
Notifications
You must be signed in to change notification settings - Fork 164
Description
Lazy
has 3 modes of operation, but it is missing the mode that would be most useful in LazyCache, namely supporting multi-threading and not caching exceptions. Since that mode is missing the current implementation will cache the exception thrown by the factory function and rethrow it for every access to the lazy. That's not a good thing when the Lazy itself is cached, as it means that every access of the cached value results in a thrown exception! More information about the problem is here: https://github.com/dotnet/corefx/issues/32337
There is a simple replacement for Lazy
that can be used instead:
public class AtomicLazy<T>
{
private readonly Func<T> _factory;
private T _value;
private bool _initialized;
private object _lock;
public AtomicLazy(Func<T> factory)
{
_factory = factory;
}
public T Value => LazyInitializer.EnsureInitialized(ref _value, ref _initialized, ref _lock, _factory);
}
This uses the same underlying LazyInitializer
as Lazy
, but it only supports one mode, the one that is missing (and, imo, most useful).
And for AsyncLazy
:
public class AsyncLazy<T>
{
private readonly Func<Task<T>> _factory;
private Task<T> _task;
private bool _initialized;
private object _lock;
public AsyncLazy(Func<Task<T>> factory)
{
_factory = factory;
}
public async Task<T> Value()
{
try
{
return await LazyInitializer.EnsureInitialized(ref _task, ref _initialized, ref _lock, _factory);
}
catch
{
Volatile.Write(ref _initialized, false);
throw;
}
}
}