C# 这个系统的实现有什么问题?懒惰?

C# 这个系统的实现有什么问题?懒惰?,c#,.net,.net-3.5,outlook-addin,C#,.net,.net 3.5,Outlook Addin,下面是一个很好的类,它实现了.NET4.0的System.Lazy的一个子集。很长一段时间以来,它一直运转良好,但今天发生了一些奇怪的事情。下面的InvalidOperationException是在调用堆栈(或任何其他线程)中找不到Lazy.Value.get的情况下抛出的,除了抛出异常的帧 public class Lazy<T> { readonly object _locker = new object(); Func<T> _func;

下面是一个很好的类,它实现了.NET4.0的System.Lazy的一个子集。很长一段时间以来,它一直运转良好,但今天发生了一些奇怪的事情。下面的InvalidOperationException是在调用堆栈(或任何其他线程)中找不到Lazy.Value.get的情况下抛出的,除了抛出异常的帧

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;
        }
    }
}
公共类
{
只读对象_locker=新对象();
Func_Func;
T_值;
忙碌;
公共服务(Func Func)
{
if(ReferenceEquals(func,null))
抛出新的ArgumentNullException(“func”);
_func=func;
}
public bool IsValueCreated{get{return}func==null;}
公共价值
{
收到
{
如果(_func!=null)
锁(储物柜)
如果(忙)
抛出新的InvalidOperationException(“函数求值递归回Value.get到同一线程上”);
else如果(_func!=null)
{
_忙=真;
尝试
{
_值=_func();
_func=null;
}
最后{u busy=false;}
}
返回_值;
}
}
}
这怎么会发生?是否有任何方法可以跳过
finally{}
块?从未命中
\u busy=true
处的断点;是否有任何方法可以将“忙碌的”默认设置为“真实”


这是在使用Addin Express进行Office 2007集成的过程中发生的,可能有一些不安全的库会弄乱Lazy的部分,或者可能是.Net framework版本兼容性问题(这是针对3.5构建的)?

就我个人而言,如果你在代码中到处都使用大括号,我会对你的代码更有信心——很容易被暗示结构不正确的空格所接受。此外,您正在使用双重检查锁定,而不使
\u func
易失性。坏主意。@JonSkeet:你能详细说明一下在使用双重检查锁定时使_func易失性的要点吗?@EricJ.:Read-while.NET的内存模型并不完全相同,但它非常接近,除非你有内存障碍,否则会出现问题。就我个人而言,我甚至会避免自己做这种事。您是否验证了一个更简单的实现(总是获得锁)实际上太慢了?这种情况发生时的一致性已经像开始时一样神秘地结束了。我决定实施Jon Skeet的“始终锁定”建议。如果我能确定这解决了问题(正如Joachim Isaksson所建议的),我会在这里发布修改后的代码作为答案。@JoshuaTacoma问题是,我看不出
\u busy
以任何方式从双重检查的锁中得到错误的值,但是,一旦您在可能的内存障碍竞争条件下走到了下坡路,就很难完全排除任何副作用,特别是因为
func()
调用未知。