Visual Studio在调用之前在调试器中计算func

时间:2017-10-16 09:22:00

标签: c# debugging lazy-loading func

我想实现自定义Lazy<T>类,只是为了实现它。有趣的是,当我将函数传递给构造函数时,在调试器中我已经可以看到该对象已在函数内创建,即使实际调用在Value内。这是因为调试器会评估_func本身,还是我不明白Func<>的工作原理?

class Program
{
    static void Main(string[] args)
    {
        var lazyObj = new LazyTest<Entity>(() => new Entity { Foo = 5 }); // Debugger shows that Entity is already created here and Foo = 5.
        var entity = lazyObj.Value; // Creation of Entity should happen here.
        Console.WriteLine(entity.Foo);

        Console.Read();
    }
}

public class Entity
{
    public int Foo { get; set; }
}

public class LazyTest<T>
{
    private T _value;
    public T Value
    {
        get
        {
            if (_value == null)
                _value = _func();
            return _value;
        }
    }
    private Func<T> _func { get; set; }

    public LazyTest(Func<T> func)
    {
        _func = func;
    }

我发现Lazy<T>内部使用了属性internal T ValueForDebugDisplay,但我不能100%确定这是否是我问题的答案。

1 个答案:

答案 0 :(得分:1)

添加断点时,调试器会显示当前作用域中存在的变量和属性的值。默认情况下,对它们进行评估,您可以通过以下几种方式处理此行为:

1)将DebuggerBrowsable Never属性添加到您的属性中,然后它的值将不会显示在locals窗口中:

[DebuggerBrowsable(DebuggerBrowsableState.Never)]

2)在Visual Studio中禁用此行为:工具 - &gt;选项 - &gt;调试 - &gt;一般 - &gt;并禁用“启用属性评估...

3)Look how Lazy does it。我们看到添加到类中的属性:

[DebuggerDisplay("ThreadSafetyMode={Mode}, IsValueCreated={IsValueCreated}, IsValueFaulted={IsValueFaulted}, Value={ValueForDebugDisplay}")]
public class Lazy<T>

您提到的属性ValueForDebugDisplay在此处实现:

internal T ValueForDebugDisplay
{
    get
    {
        if (!IsValueCreated)
        {
             return default(T);
        }
        return ((Boxed)m_boxed).m_value;
    }
}

正如您所看到的,该值尚未创建,它显示了Lazy泛型类型的默认值。