实现没有CA警告的固有IDisposable模式

本文关键字:IDisposable 模式 警告 CA 实现 | 更新日期: 2024-09-17 00:03:57

我正在处理以下情况。我有一个基类,它有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)。

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

实现没有CA警告的固有IDisposable模式

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

要了解更多详细信息,以及更清晰的替代API,请查看:

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

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

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

这是个坏主意。相反,让你所有的课程都分为一到两类:

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

理想情况下,您甚至不需要任何这样的类,但可以使用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()和finalizer中做同样的事情,除了前者调用GC.SuppressFinalize,要么我们有简单的无托管拥有类只调用Dispose()它们需要处理的一切,包括在必要时调用base.Dispose(),并且没有finalizer。不需要在同一类中将逻辑拆分为两种类型。没有最终确定者调用已最终确定的内容的风险,也没有将超过必要的内容强制加入最终确定队列的风险。

理想情况下,你甚至从来没有做过第一种类型。只是第二种。

如果你是从另一方的班级继承的,那么就这么做吧:

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

不要自己处理disposing == false的情况,因为其中没有混合的非托管资源。

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

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