处理后的闭包有奇怪的行为

a disposed closure has a strange behavior

我有一个这样的一次性 class :

public class Person:IDisposable
{
    public string Name{get;set;}

    public void Dispose()
    {}
}

这是一组扩展方法,如果调用者为 null,returns 为默认值:

static class Extensions
{

    public class Option<T>
    {
        private readonly Func<T> _resultGetter;

        public bool HasValue { get; }

        public Option(Func<T> resultGetter, bool hasValue)
        {
            _resultGetter = resultGetter;
            HasValue = hasValue;
        }

        public T Value => _resultGetter();
    }

    public static Option<TResult> SafeGetter<T, TResult>(this T self, Func<T, TResult> getter, Func<TResult> defaultGetter = null) where T : class
    {
        defaultGetter = defaultGetter ?? (() => default(TResult));
        return new Option<TResult>(self == null ? defaultGetter :()=> getter(self),self!=null);
    }
}

如您所见,SafeGetter 方法 returns 一个 Option 对象,该对象具有一个 getter 函数,该函数具有一个 self 参数作为闭包。

所以为了在处理对象后测试 getter 函数,我写了一个这样的测试:

public void SafeGetterDisposableTest()
{
    Extensions.Option<string> nameGetter; 
    using (var john = new Person { Name = "John" })
    {
        nameGetter = john.SafeGetter(x => x.Name);
    }
    Console.WriteLine(nameGetter.Value);
}

如您所见,我获得了 Option 对象并在 john 被释放后调用它。我以为我会得到一个例外,但令我惊讶的是测试正在运行。 为什么会这样?这段代码是否会以某种方式引入内存泄漏?

I thought that I would get an exception but to my surprise the test is working.

您不会仅通过简单地实施 IDisposable 收到 ObjectDisposedException(或与此相关的任何其他异常)。您的 Dispose 方法是 empty,并且即使在您的 using 语句调用它之后也不会改变该对象。如果在处理对象后更改它以在 getter 中抛出异常,您将得到一个异常。否则什么也不会发生。

约定 IDisposable 对象的实现方式是,当它们的成员在被释放后被访问时会抛出异常。这不是语言的行为。如果您的一次性对象实际上有一个正在使用的非托管资源,然后被清理,那么即使您没有明确抛出,您在处理后执行的操作也可能无法正常工作,因此约定。