Skip to content

Instantly share code, notes, and snippets.

@michel-pi
Created September 30, 2018 22:47
Show Gist options
  • Save michel-pi/d3500b6297553c6006333c996b0d284f to your computer and use it in GitHub Desktop.
Save michel-pi/d3500b6297553c6006333c996b0d284f to your computer and use it in GitHub Desktop.
How Lazy<T> should have been implemented
using System;
using System.Threading;
namespace System
{
public class LazyType<T>
{
private static readonly Func<T> DefaultValueFactory = () => default(T);
private readonly object _lock;
private readonly LazyThreadSafetyMode _threadSafetyMode;
private readonly Func<T> _valueFactory;
private Exception _cachedException;
private T _value;
public bool IsValueCreated { get; private set; }
public T Value
{
get
{
if (IsValueCreated) return _value;
if (_threadSafetyMode == LazyThreadSafetyMode.None)
{
_value = _valueFactory();
IsValueCreated = true;
return _value;
}
else if (_threadSafetyMode == LazyThreadSafetyMode.PublicationOnly)
{
if (_cachedException != null) throw _cachedException;
T tmp;
try
{
tmp = _valueFactory();
}
catch (Exception ex)
{
_cachedException = ex;
throw;
}
lock (_lock)
{
if (IsValueCreated) return _value;
_value = tmp;
IsValueCreated = true;
return _value;
}
}
else
{
lock (_lock)
{
if (_cachedException != null) throw _cachedException;
if (IsValueCreated) return _value;
try
{
_value = _valueFactory();
}
catch (Exception ex)
{
_cachedException = ex;
throw;
}
IsValueCreated = true;
return _value;
}
}
}
set
{
_value = value;
IsValueCreated = true;
}
}
public LazyType()
{
_valueFactory = DefaultValueFactory;
}
public LazyType(LazyThreadSafetyMode threadSafetyMode)
{
_threadSafetyMode = threadSafetyMode;
if (threadSafetyMode != LazyThreadSafetyMode.None) _lock = new object();
_valueFactory = DefaultValueFactory;
}
public LazyType(bool isThreadSafe)
{
_threadSafetyMode = isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None;
if (isThreadSafe) _lock = new object();
_valueFactory = DefaultValueFactory;
}
public LazyType(Func<T> valueFactory)
{
_valueFactory = valueFactory ?? throw new ArgumentNullException(nameof(valueFactory));
}
public LazyType(Func<T> valueFactory, bool isThreadSafe)
{
_valueFactory = valueFactory ?? throw new ArgumentNullException(nameof(valueFactory));
_threadSafetyMode = isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None;
if (isThreadSafe) _lock = new object();
}
public LazyType(Func<T> valueFactory, LazyThreadSafetyMode threadSafetyMode)
{
_valueFactory = valueFactory ?? throw new ArgumentNullException(nameof(valueFactory));
_threadSafetyMode = threadSafetyMode;
if (threadSafetyMode != LazyThreadSafetyMode.None) _lock = new object();
}
public override string ToString()
{
return _value.ToString();
}
public static implicit operator T(LazyType<T> lazy)
{
return lazy.Value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment