被处理的闭包有一个奇怪的行为
本文关键字:有一个 处理 闭包 | 更新日期: 2023-09-27 18:19:20
我有一个像这样的一次性类:
public class Person:IDisposable
{
public string Name{get;set;}
public void Dispose()
{}
}
,这里有一组扩展方法,如果调用者为null,则返回默认值:
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
方法返回一个Option
对象,该对象有一个getter函数,该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被处置后调用它。我以为我会得到一个异常,但令我惊讶的是,测试是有效的。为什么会发生这种情况?这段代码是否以某种方式引入了内存泄漏?
我认为我会得到一个异常,但令我惊讶的是,测试是工作。
仅仅通过简单地实现IDisposable
,您不会收到ObjectDisposedException
(或任何其他异常)。您的Dispose
方法是空,并且即使在被您的using
语句调用之后也不会更改对象。如果你改变它,在对象被处置后在getter中抛出异常,你将得到一个异常。
这是约定实现IDisposable
对象时,当其成员在被处置后被访问时抛出异常。这不是语言的行为。如果您的一次性对象实际上有一个它正在使用的非托管资源,然后被清理,那么在它被处理后执行的操作可能无法正常工作,即使您没有显式抛出,因此约定