问题
After reading the answer here, I decided to mark my class as sealed in order to simplify the IDisposable implementation. Why does sealed affect the implementation of IDisposable (e.g. GC.SuppressFinalize(this);
does not need to be called)? Please explain what is happening. I need to be able to explain to a fellow developer why I made the class sealed.
回答1:
If a class which implements IDisposable
is not sealed, it is likely that a derived class will need to do something in response to Dispose
, but the base-class actions for Dispose
should be performed as well. If the class exposes a public Dispose
member which will always be synonymous with IDisposable.Dispose
, the necessary semantics could be achieved in C# by simply using implicit interface implementation with a public virtual Dispose
method.
There are two problems with that approach:
- It would require derived classes use a different method in cases where the parent exposes a public `Dispose` method, than in cases where it does not; things could get very muddy if a class which doesn't expose a public `Dispose` method is inherited by an unsealed class which does.
- Some base disposal code should run before the derived-class disposal code (e.g. the code that suppresses repeated `Dispose` attempts), and some should run after (e.g. `GC.SuppressFinalize()`). The only way to achieve that is to have a non-virtual wrapper call a protected virtual function. Note, btw, that Microsoft's wrapper doesn't properly suppress repeated-`Dispose`, but the wrapper is the only good place for such suppression code.
Note that Microsoft seems to have intended its Dispose
pattern to be used in the cases where a base class does not override Finalize
, but a derived class uses Finalize
for cleanup. While that may have been the intent, it is not a good pattern for that purpose. With very few exceptions, the only classes which should only override Finalize
for cleanup are those which derive from trivial classes like Object
. If a class implements IDisposable
but does not override Finalize
, the only purpose for which a derived class should override Finalize
is to sound an alarm if Finalize
ever gets called, and even that usage is debatable (a better pattern would be:
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()
class is assumed to be a class with an overridden Finalize()
method which sounds an alarm if that Finalize()
method gets called without its Dispose()
method being called first. The Dispose
method for whatever
will ensure that, if the derived-class method returns properly, the alarm will get cancelled. Note that if an instance of whatever
has an unsuppressed finalizer, everything to which whatever
holds a direct or indirect reference will have to be kept around until that finalizer has either run or been suppressed. By contrast, the addition of a DisposalAlarm
object does not extend the lifetime of anything in whatever
.
回答2:
Making a class sealed
means that there can be no classes derived from it. That means that the implementation of IDisposable
doesn't need to take into account the behavior (or misbehavior) of derived classes.
回答3:
A sealed class is not intended to be used as a base class, while an unsealed class is. Hence lies the distinction: an unsealed class needs to provide a way for its derived classes to implement Dispose()
of their own, while a sealed class is free of this responsibility, because it cannot be extended.
来源:https://stackoverflow.com/questions/11024336/why-does-sealed-affect-the-implementation-of-idisposable