在阅读答案here后,我决定将我的课程标记为已密封,以简化IDisposable实施。密封为什么会影响IDisposable的实现(例如GC.SuppressFinalize(this);
不需要调用)?请解释一下发生了什么。我需要能够向同事解释为什么我把课程密封了。
答案 0 :(得分:2)
如果实现IDisposable
的类没有被密封,则派生类可能需要做一些事情来响应Dispose
,但是Dispose
的基类操作也应该进行。如果类公开了一个永远与Dispose
同义的公共IDisposable.Dispose
成员,那么只需使用带有公共虚拟Dispose
方法的隐式接口实现,就可以在C#中实现必要的语义。 / p>
这种方法存在两个问题:
请注意,Microsoft似乎打算在基类不覆盖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(); } } }
假定DisposalAlarm()
类是一个具有重写Finalize()
方法的类,如果在没有首先调用Finalize()
方法的情况下调用Dispose()
方法,则会发出警报。 Dispose
的{{1}}方法将确保,如果派生类方法正确返回,则警报将被取消。请注意,如果whatever
的实例具有未抑制的终结器,则whatever
持有直接或间接引用的所有内容都必须保留,直到该终结器已运行或已被抑制。相比之下,添加whatever
对象不会延长DisposalAlarm
中任何内容的生命周期。
答案 1 :(得分:1)
创建类sealed
意味着不能从中派生类。这意味着IDisposable
的实现不需要考虑派生类的行为(或错误行为)。
答案 2 :(得分:1)
密封类不打算用作基类,而未密封的类则用作基类。因此存在区别:未密封的类需要为其派生类提供一种方法来实现它们自己的Dispose()
,而密封类则没有这个责任,因为它无法扩展。