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