Snoozy: A lazy reevaluation upon get I would appreciate critique and comments in regards of thread-safety on a basic type I'm trying to create.

In C#, the Lazy&lt;T&gt; type is initialized only once, and only when needed the first time.

My type, called Snoozy&lt;T&gt;, is similar, but differs in one important aspect:

The value can be reinitialized when necessary (but only when read).

The purpose is to not perform the value factorization unless someone needs the new value. This could prevent e.g. unnecessary heavy calculations.

Example: A bank account stores a long list of events describing withdrawals and deposits. To get the current balance, all transactions need to be summed up. This could potentially be a very CPU-intensive operation, but the adding of new transactions is rare whereas reading the balance is frequent. When adding a new transaction, there is really no need to recalculate the balance until someone explicitly wants to read it.

This is the code I've come up with so far:

public class Snoozy&lt;T&gt;
{
    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    private readonly Func&lt;T&gt; _factory;
    private T _value;
    private bool _isStale;

    public Snoozy(Func&lt;T&gt; valueFactory)
    {
        _factory = valueFactory;
        _isStale = true;
    }

    public T Value
    {
        get
        {
            _lock.EnterUpgradeableReadLock();

            if (_isStale)
            {
                _lock.EnterWriteLock();

                _value = _factory();
                _isStale = false;

                _lock.ExitWriteLock();
            }

            _lock.ExitUpgradeableReadLock();

            return _value;
        }
    }

    // This is how the consumer signals that the underlaying value has changed.
    public void Poke()
    {
        _lock.EnterWriteLock();
        _isStale = true;
        _lock.ExitWriteLock();
    }

    public static implicit operator Snoozy&lt;T&gt;(T value)
    {
        return new Snoozy&lt;T&gt;(() =&gt; value);
    }

    public static implicit operator T(Snoozy&lt;T&gt; snoozy)
    {
        return snoozy.Value;
    }
}
I have some bad news for you... According to MSDN only one thread can enter an upgradeable read lock:


  Only one thread can enter upgradeable mode at any given time. If a thread is in upgradeable mode, and there are no threads waiting to enter write mode, any number of other threads can enter read mode, even if there are threads waiting to enter upgradeable mode.


That means your current implementation is basically just exclusive locking.



You should validate your parameters:

public Snoozy(Func&lt;T&gt; valueFactory)
{
    if (valueFactory == null)
    {
        throw new ArgumentNullException(nameof(valueFactory));
    }


and likewise in your conversions.



On the whole, this feels like a cached value to me - there are probably existing constructs which would suit your needs better depending on what framework/type of app you're building. Rolling your own cache is hard.
Remember, there are only 2 hard problems in programming: naming, cache invalidation and off by one errors.