1

我正在处理以下案例。我有一个具有 IDisposable 模式的基类,这意味着它具有public virtual Dispose()方法和protected virtual Dispose(bool)方法。但是我无法在派生类中以不会收到任何 CA 警告的方式实现此模式。请考虑以下示例:

public class UtilizeClass : IDisposable
{
    private MyData data;

    public UtilizeClass()
    {
        data = new MyData();
    }

    public void Dispose()
    {
        data.Dispose(); // Cannot use Dispose(bool) because it is protected.
    }
}

public class MyData : Base, IDisposable
{
    // Here we have some managed resources that must be disposed.

    // How to implement the pattern?
}

public class Base : IDisposable
{
    public virtual void Dispose() { }
    protected virtual void Dispose(bool disposing) { }
}

我一直在课堂上收到相互矛盾的 CA 警告MyData。例如:删除 Dispose() 并将其逻辑移至 Dispose(bool)。

非常感谢您的回答和帮助。

4

3 回答 3

2

您的基类不应该void Dispose()是虚拟的,它应该被实现并调用虚拟void Dispose(bool disposing)作为其实现的一部分。

有关更多详细信息以及更清晰的备用 API,请查看:

http://haacked.com/archive/2005/11/18/acloserlookatdisposepattern.aspx

于 2012-08-03T12:42:15.333 回答
2

如果Base是你自己的类,那么不要实现这个反模式。

Dispose当一个类同时包含必须释放的托管资源(例如,应该有自己调用的 Stream 对象)和必须清理的非托管资源时,使用双重处理(如果处理为真,则为假) 。向上。

这是一个坏主意。而是让您的所有课程都属于一两个类别:

A. 只有非托管资源的类。理想情况下,每个班级只有一个:

public sealed class HandlesUnmanaged : IDisposable
{
  private IntPtr _someUnmanagedHandleOfSomeKind;
  public string DoSomething(string someParam)
  {
    // your useful code goes here;
    // make it thin, non-virtual and likely to be inlined
    // if you need to extend functionality, but it in a
    // containing Disposable class, not a derived class.
  }
  private void CleanUp()
  {
    //your code that cleans-up someUnmanagedHandleOfSomeKind goes here
  }
  public void Dispose()
  {
    CleanUp();
    GC.SuppressFinalize(this);//finaliser not needed now.
  }
  ~HandlesUnmanaged()//not called if already disposed
  {
    CleanUp();
  }
}

理想情况下,您甚至不需要像这样的任何类,而是使用SafeHandlewhich 为您做这些。

B. 具有一个或多个需要处置的托管资源的类:

public class NoUnmanaged : IDisposable
{
  private HandlesUnmanaged _likeAbove;
  private Stream _anExampleDisposableClass;
  public virtual void Dispose()
  {
    _likeAbove.Dispose();
    _anExampleDisposableClass.Dispose();
  } 
  /* Note no finaliser, if Dispose isn't called, then _likeAbove's
  finaliser will be called anyway. All a finaliser here would do is
  slow things up and possibly introduce bugs.
  */
}
public class DerivedNoUnManaged : NoUnmanaged
{
  Stream _weMayOrMayNotHaveAnotherDisposableMember;
  public override void Dispose()
  {
    //note we only need this because we have
    //another disposable member. If not, we'd just inherit
    //all we need.
    base.Dispose();
    weMayOrMayNotHaveAnotherDisposableMember.Dispose();
  }
}

总之,我们要么有简单的非托管拥有类,它们在它们Dispose()和它们的终结器中做同样的事情,除了前调用GC.SuppressFinalize,或者我们有简单的非非托管拥有类,它们只是Dispose()他们需要处理的所有东西,包括如有必要,请致电base.Dispose(),并且没有终结者。无需将逻辑拆分为同一类中的两种类型。终结者没有风险调用已经终结的东西,或者强制超过必要的东西进入终结队列。

理想情况下,你甚至根本不做第一种类型。只是第二种。

如果您通过从另一方的类继承而被迫进入它,那么只需执行以下操作:

public MyClass : Base
{
  Stream _forExample;
  public override void Dispose(bool disposing)
  {
    if(disposing)
    {
      _forExample.Dispose();
    }
    base.Dispose(disposing);
  }
}

不要disposing == false自己处理这种情况,因为那里没有混入非托管资源。

于 2012-08-03T13:01:48.460 回答
0

基类应该有一个public void Dispose()(非虚拟的)调用Dispose(true).

派生类应该简单地覆盖protected virtual void Dispose(bool disposing).

于 2012-08-03T12:42:19.793 回答