实现继承的IDisposable模式,没有CA警告

时间:2012-08-03 12:38:40

标签: c# .net idisposable

我正在处理以下案件。我有一个具有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) { }
}

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

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

3 个答案:

答案 0 :(得分:2)

您的基类不应该是void Dispose()虚拟,应该实现它并在实现过程中调用虚拟void Dispose(bool disposing)

有关详细信息以及更清晰的替代API,请查看:

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

答案 1 :(得分:2)

如果Base是您自己的类,则不要实现此反模式。

当一个类包含必须处理的两个托管资源时(例如,应该将其自己的Dispose调用的Stream对象),使用双重部署(一个如果处置为true,一个如果为false)和必须清理的非托管资源。

这是一个坏主意。相反,所有课程都适合一两个类别:

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

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

理想情况下,您甚至不需要任何类似这样的课程,但请使用SafeHandle为您执行此操作。

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案例,因为那里没有混合非托管资源。

答案 2 :(得分:0)

基类应该有public void Dispose()(非虚拟),可以调用Dispose(true)

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