English 中文(简体)
如何更好地执行。 NET IDisposable categories?
原标题:How to better implement .NET IDisposable classes?

如果这个问题太不限,则提前通知我,但我在这里看到了类似的语言讨论员额,因此,我看一看lung。

无论如何,我阅读了几个MSDN求助页面和适当实施<代码>的其他博客。 IDisposable categories. 我认为,我对事情的理解非常好,但我不得不问,所建议的班级结构是否存在缺陷:

public class DisposableBase : IDisposable
{
    private bool mDisposed;

    ~DisposableBase()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!mDisposed)
        {
            if (disposing)
            {
                // Dispose managed resources
                mManagedObject.Dispose();
            }

            // Dispose unmanaged resources
            CloseHandle(mUnmanagedHandle);
            mUnmanagedHandle = IntPtr.Zero;

            mDisposed = true;
        }
    }
}

以上所述的任何时间都应作为基类,你依靠子级的执行者在必要时适当推翻处置(毛)方法。 简言之,衍生产品必须保证它们在其压倒性版本中采用基本处置方法。 否则,无法管理的基类资源就永远得不到释放,从而打败了可开发的接口的主要目的。

We all know the benefits of virtual methods, but it seems like in this case their design falls short. In fact, I think this particular shortcoming of virtual methods manifests itself frequently when trying to design visual components and similar base/derived class structures.

Consider the following change, using a protected event rather than a protected virtual method:

public class DisposeEventArgs : EventArgs
{
    public bool Disposing { get; protected set; }

    public DisposeEventArgs(bool disposing)
    {
        Disposing = disposing;
    }
}

public class DisposableBase : IDisposable
{
    private bool mDisposed;

    protected event EventHandler<DisposeEventArgs> Disposing;

    ~DisposableBase()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // This method is now private rather than protected virtual
    private void Dispose(bool disposing)
    {
        if (!mDisposed)
        {
            // Allow subclasses to react to disposing event
            AtDisposing(new DisposeEventArgs(disposing));

            if (disposing)
            {
                // Dispose managed resources
                mManagedObject.Dispose();
            }

            // Dispose unmanaged resources
            CloseHandle(mUnmanagedHandle);
            mUnmanagedHandle = IntPtr.Zero;

            mDisposed = true;
        }
    }

    private void AtDisposing(DisposeEventArgs args)
    {
        try
        {
            EventHandler<DisposeEventArgs> handler = Disposing;
            if (handler != null) handler(this, args);
        }
        catch
        {
        }
    }
}

With this design, the base class Dispose(bool) method will always be called, regardless of whether subclasses subscribe to the Disposing event or not. The biggest flaw that I can see with this revised setup is that there is no predetermined order for when event listeners are called. This could be problematic if there are multiple levels of inheritance, e.g. SubclassA s listener might be triggered before its child SubclassB s listener. Is this flaw serious enough to invalidate my revised design?

这一设计难题使我想到的是,对于与<代码>virtual<<>code>相似的方法,有某种变式,但将确保基类方法总是被称作,即使子类取代了这一功能。 如果能更好地做到这一点,我将非常赞赏你的建议。

最佳回答

如果你真想使用virtual等继承机制,请在此重新使用。 对于像我这样想确保我执行的设想,总是有人要求,但希望允许基类定制,我采用以下模式:

private void Dispose(bool disposing)
  if (mDisposed) { 
    return;
  }

  if (disposing) {
    mManagedObject.Dispose();
  }

  // Dispose unmanaged resources
  CloseHandle(mUnmanagedHandle);
  mUnmanagedHandle = IntPtr.Zero;
  mDisposed = true;

  DisposeCore(disposing);
}

protected virtual void DisposeCore(bool disposing) {
  // Do nothing by default
}

模式 我确保了我的基本班次<代码>Dispose的执行始终被称作。 选修课只会使我停止使用基数方法。 它们仍然可以选择采用压倒式的<代码>DisposeCore的处置方式,但不能中断基类合同。

问题回答

衍生的类别可以简单地重新实施<代码> 可转让<>代码>,从而防止您的处置方法被称作“,因此,你可以确保这两种方法。

我个人不使用这两种模式。 我更希望以<代码>SafeHandle和类似机制为基础,而不是执行定稿者本人。

认为显然,不把持反对意见称为这样一人会赶上它。 当然,只有根据德国地理和地理统计局汇编人员指令汇编该守则时,才会使用“Debug.WriteLine。

public class DisposableBase : IDisposable
{
  private bool mDisposed;

  ~DisposableBase()
  {
      if (!mDisposed)
         System.Diagnostics.Debug.WriteLine ("Object not disposed: " + this + "(" + GetHashCode() + ")";
      Dispose(false);
  }

  public void Dispose()
  {
      Dispose(true);
      GC.SuppressFinalize(this);
  }

You can break it down:

  • A destructor (finalizer) is only needed for unmanaged resources.
  • Using a Safehandle can turn an unmanged resource into a managed resource.
  • Ergo: You won t need a destructor. That halves the Dispose pattern.

参考设计采用<代码>虚拟处置(bool),以适应基地/衍生阶级问题。 这使得衍生产品类别的负担要到<编码>基准。 议题的核心是处置(处置)。 我采用两种办法:

1) Prevent it. With a sealed base-class you won t have to worry.

sealed class Foo:IDisposable 
{ 
   void Dispose() { _member.Dispose(); } 
}

2) Check it. Like @j-agent s answer but conditional. When performance could be an issue then you don t want the finalizers in Production code:

class Foo:IDisposable 
{ 
  void Dispose() { Dispose(true); }

  [Conditional("TEST")]  // or "DEBUG"
  ~Foo { throw new InvalidOperation("somebody forgot to Dispose") } 
}

无论任何次流层压倒处置(可能通过压倒性或新),都不会被称作是谁,但你的主子将被叫作(可变基本法),这样就可以有一个良好的起点。

http://www.c-sharpcorner.com/UploadFile/chandrahundigam/underontDestructors11192005021208AM/UnderentDestructors.aspx”rel=“nofollow”http://www.c-sharpiqueer.com/UploadFile/chandrahundigam/underDestructors11192005021208AM/underDestructors.aspx





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签