看完答案后here,我决定将我的课程标记为密封以简化I一次性执行。为什么sealed会影响IDisposable的实现(例如GC.SuppressFinalize(this);
不需要调用)?请解释发生了什么事。我需要能够向其他开发人员解释为什么我要密封该类。
如果一个类实现了IDisposable
没有密封,派生类可能需要做一些事情来响应Dispose
,但是基类动作Dispose
也应该执行。如果该类公开了 publicDispose
永远是同义词的成员IDisposable.Dispose
,通过简单地使用带有公共虚拟的隐式接口实现,可以在 C# 中实现必要的语义Dispose
method.
这种方法有两个问题:
- 它要求派生类在父类公开公共“Dispose”方法的情况下使用与不公开“Dispose”方法的情况不同的方法;如果一个不公开“Dispose”方法的类被一个公开“Dispose”方法的未密封类继承,那么事情可能会变得非常混乱。
- 一些基本处理代码应该在派生类处理代码之前运行(例如,禁止重复尝试“Dispose”的代码),而有些则应该在派生类处理代码之后运行(例如“GC.SuppressFinalize()”)。实现这一点的唯一方法是让非虚拟包装器调用受保护的虚拟函数。请注意,顺便说一句,微软的包装器不能正确抑制重复的“Dispose”,但包装器是此类抑制代码的唯一好地方。
请注意,微软似乎有意Dispose
在基类不重写的情况下使用的模式Finalize
,但派生类使用Finalize
用于清理。虽然这可能是意图,但这并不是一个好的模式。除了极少数例外,唯一应该重写的类Finalize
用于清理的是那些派生自琐碎类的类,例如Object
。如果一个类实现了IDisposable
但不覆盖Finalize
,派生类应该重写的唯一目的Finalize
是发出警报,如果Finalize
曾经被调用过,甚至这种用法也是有争议的(更好的模式是:
class whatever:IDisposable
{
IDisposable DisposedStatusObject;
// Generate a static dummy object instance we can use as a sentinel value
// It needs to be `IDisposable`, but shouldn't actually hold any resources.
static IDisposable DisposedStatusDisposed = new List<int>().GetEnumerator();
public bool Disposed {get {return (DisposedStatusObject == DisposedStatusDisposed);} }
whatever()
{
DisposedStatusObject = new DisposalAlarm(); // First thing in constructor
}
void Dispose()
{
IDisposable prevStatus;
prevStatus = Interlocked.Exchange(DisposedStatus, DisposedStatusDisposed);
if (prevStatus != DisposedStatusDisposed)
{
Dispose(true);
prevStatus.Dispose();
}
}
}
The DisposalAlarm()
假设类是一个被重写的类Finalize()
如果出现这种情况,则发出警报的方法Finalize()
方法在没有它的情况下被调用Dispose()
首先调用的方法。这Dispose
方法用于whatever
将确保,如果派生类方法正确返回,则警报将被取消。请注意,如果一个实例whatever
有一个不受抑制的终结器,一切都whatever
持有直接或间接引用的对象必须保留,直到终结器运行或被抑制。相比之下,添加一个DisposalAlarm
对象不会延长任何对象的生命周期whatever
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)