本文介绍了为什么“密封”会影响IDisposable的实施?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读答案后,我决定将我的班级标记为为了简化的实现。为什么密封会影响IDisposable的实现(例如 GC.SuppressFinalize(this); 不需要调用)?请解释发生了什么。我需要能够向开发人员解释为什么我将类密封了。

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.

推荐答案

如果一个类实现了 IDisposable 没有密封,很可能派生类将需要对 Dispose 做一些响应,但是基类- Dispose 的类动作也应执行。如果该类公开了一个公共 Dispose 成员,该成员将始终与 IDisposable.Dispose 同义,则可以实现必要的语义在C#中,只需将隐式接口实现与公共虚拟 Dispose 方法结合使用即可。

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.

这种方法有两个问题:


  1. 与父类公开的公共Dispose方法相比,要求派生类使用不同的方法才不是;如果未公开公共 Dispose方法的类被未公开的类继承,则情况可能会变得非常混乱。
  2. 某些基本处理代码应在派生类处理代码之前运行(例如,禁止重复执行 Dispose尝试的代码),而某些应在其后运行(例如 GC.SuppressFinalize())。实现此目标的唯一方法是让非虚拟包装程序调用受保护的虚拟函数。顺便说一句,微软的包装器并不能正确地抑制重复的 Dispose,但是包装器是此类抑制代码的唯一好地方。
  1. 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.
  2. 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.

请注意,Microsoft似乎打算将其 Dispose 模式用于以下情况:基类不会覆盖 Finalize ,但是派生类使用 Finalize 进行清理。虽然这可能是目的,但这不是实现此目的的好模式。除极少数例外外,唯一应覆盖 Finalize 进行清理的类是从诸如 Object 之类的琐碎类派生的类。如果一个类实现了 IDisposable 但没有覆盖 Finalize ,则派生类应覆盖<$ c的唯一目的$ c> Finalize 会在 Finalize 被调用时发出警报,即使用法也值得商((更好的模式是:

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();
    }
  }
}

DisposalAlarm()类是具有覆盖的 Finalize()方法的类,如果该 Finalize()方法时不会先调用其 Dispose()方法。 任何内容 Dispose 方法将确保,如果派生类方法正确返回,则警报将被取消。请注意,如果任何的实例具有未抑制的终结器,则任何拥有直接或间接引用的所有对象都将具有一直保持到该终结器运行或被抑制为止。相比之下,添加 DisposalAlarm 对象并不会延长任何中任何东西的寿命。

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.

这篇关于为什么“密封”会影响IDisposable的实施?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 22:32
查看更多