C#abstract Dispose方法

Sar*_*els 8 c# abstract-class dispose static-analysis

我有一个实现IDisposable的抽象类,如下所示:

public abstract class ConnectionAccessor : IDisposable
{
    public abstract void Dispose();
}
Run Code Online (Sandbox Code Playgroud)

在Visual Studio 2008 Team System中,我在项目上运行了代码分析,其中一个警告如下:

Microsoft.Design:修改'ConnectionAccessor.Dispose()'以便它调用Dispose(true),然后在当前对象实例上调用GC.SuppressFinalize(在Visual Basic中为'this'或'Me'),然后返回.

它只是愚蠢,告诉我修改抽象方法的主体,还是应该在任何派生实例中做进一步的事情Dispose

Pav*_*aev 12

您应该遵循传统的实施模式Dispose.制作Dispose()虚拟被认为是不好的做法,因为传统模式强调的代码重用在"管理清理"(API调用客户Dispose()直接或通过using)和"非托管清理"(GC呼吁终结).提醒一下,模式是这样的:

public class Base
{
    ~Base()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this); // so that Dispose(false) isn't called later
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
             // Dispose all owned managed objects
        }

        // Release unmanaged resources
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的关键是终结器和Dispose非托管清理之间没有重复,但是任何派生类都可以扩展托管和非托管清理.

对于您的情况,您应该做的是:

protected abstract void Dispose(bool disposing)
Run Code Online (Sandbox Code Playgroud)

并保留其他所有内容.即使这是值得怀疑的,因为你现在正在强制执行你的派生类Dispose- 你怎么知道它们都需要它?如果您的基类没有任何可处置的东西,但是大多数派生类可能会执行(可能有一些例外),那么只需提供一个空实现.这是System.IO.Stream(本身是抽象的)所做的,所以有先例.


dtb*_*dtb 10

警告基本上告诉您在类中实现Dispose模式.

生成的代码应如下所示:

public abstract class ConnectionAccessor : IDisposable
{
    ~ConnectionAccessor()
    {
        Dispose(false);
    }

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

    protected virtual void Dispose(bool disposing)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 提及模式的+1,并指出Dispose(bool)应该是派生类应该实现或覆盖的虚拟/抽象方法,而不是Dispose(). (3认同)

akm*_*mad 5

虽然这看起来确实有点挑剔,但这个建议是有效的。您已经表明您希望 ConnectionAccessor 的任何子类型都将拥有需要处理的内容。因此,确保基类完成正确的清理(就 GC.SuppressFinalize 调用而言)似乎比依赖每个子类型来完成似乎更好。

我使用 Bruce Wagners 的书《Effective C#》中提到的处置模式,它基本上是:

public class BaseClass : IDisposable
{
    private bool _disposed = false;
    ~BaseClass()
    {
        Dispose(false);
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            //release managed resources
        }

        //release unmanaged resources

        _disposed = true;
    }
}

public void Derived : BaseClass
{
    private bool _disposed = false;

    protected override void Dispose(bool disposing)
    {
        if (_disposed) 
            return;

        if (disposing)
        {
            //release managed resources
        }

        //release unmanaged resources

        base.Dispose(disposing);
        _disposed = true;
    }
Run Code Online (Sandbox Code Playgroud)