Here is a nice class that implements a subset of .Net 4.0's System.Lazy. It's been working fine for quite some time, but today something odd happened. The InvalidOperationException, below, was thrown in a case where Lazy.Value.get was nowhere to be found in the call stack (or in any other thread for that matter) except for the frame that was throwing the exception.
public class Lazy<T>
{
readonly object _locker = new object();
Func<T> _func;
T _value;
bool _busy;
public Lazy(Func<T> func)
{
if (ReferenceEquals(func, null))
throw new ArgumentNullException("func");
_func = func;
}
public bool IsValueCreated { get { return _func == null; } }
public T Value
{
get
{
if (_func != null)
lock (_locker)
if (_busy)
throw new InvalidOperationException("Function evaluation recursed back into Value.get on the same thread.");
else if (_func != null)
{
_busy = true;
try
{
_value = _func();
_func = null;
}
finally { _busy = false; }
}
return _value;
}
}
}
How could this happen? Is there any way the finally{}
block could have been skipped? A breakpoint at _busy=true
was never hit; is there any way _busy
could have defaulted to true
?
This is happening in the midst of an Office 2007 integration using Addin Express, could there be some unsafe libraries messing with Lazy's bits, or maybe a .Net framework version compatibility issue (this was built targetting 3.5)?