簡體   English   中英

C#abstract Dispose方法

[英]C# abstract Dispose method

我有一個實現IDisposable的抽象類,如下所示:

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

在Visual Studio 2008 Team System中,我在項目上運行了代碼分析,其中一個警告如下:

Microsoft.Design:修改'ConnectionAccessor.Dispose()'以便它調用Dispose(true),然后在當前對象實例上調用GC.SuppressFinalize(在Visual Basic中為'this'或'Me'),然后返回。

它只是愚蠢,告訴我修改抽象方法的主體,還是應該在任何派生的Dispose實例中做進一步的事情?

您應該遵循傳統模式來實現Dispose 使Dispose()虛擬被認為是不好的做法,因為傳統模式強調在“托管清理”(API客戶端直接或通過using調用Dispose() )和“非托管清理”(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
    }
}

這里的關鍵是終結器和Dispose之間沒有重復的非托管清理,但任何派生類都可以擴展托管和非托管清理。

對於您的情況,您應該做的是:

protected abstract void Dispose(bool disposing)

並保留其他所有內容。 即使這是值得懷疑的,因為你現在正在強制你的派生類來實現Dispose - 你怎么知道所有這些都需要它? 如果您的基類沒有任何可處置的東西,但是大多數派生類可能會執行(可能有一些例外),那么只需提供一個空實現。 這是System.IO.Stream (本身是抽象的)所做的,所以有先例。

警告基本上告訴您在類中實現Dispose模式

生成的代碼應如下所示:

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

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

    protected virtual void Dispose(bool disposing)
    {
    }
}

到目前為止,我對答案的唯一抱怨是,他們都認為你需要有一個終結器,但情況不一定如此。 最終確定會產生相當大的性能開銷,如果沒有必要,我不希望對所有派生類強加。

請參閱Joe Duffy撰寫的這篇博文 ,其中介紹了何時可能需要或不需要終結器,以及如何在任何一種情況下正確實現Dispose模式。
總結Joe的博客文章,除非你正在做一些相當低級別的處理非托管內存的事情,否則你不應該實現終結器。 作為一般經驗法則,如果您的類僅保存對自身實現IDisposable的托管類型的引用,則不需要終結器(但應實現IDisposable並處置這些資源)。 如果直接從代碼中分配非托管資源(PInvoke?)並且必須釋放這些資源,則需要一個。 派生類總是可以添加一個終結器,如果它真的需要它,但是通過將它放在基類中強制所有派生類都有一個終結器會導致所有派生類受到最終化對象的性能損失的影響,而這可能不是必要。

雖然看起來有點像挑選,但建議是有效的。 您已經指出您希望ConnectionAccessor的任何子類型都有他們需要處理的東西 因此,最好確保基類完成正確的清理(就GC.SuppressFinalize調用而言),而不是依賴於每個子類型來完成它。

我使用Bruce Wagners提到的有效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;
    }

但警告很有意思。 C#設計師之一Eric Lippert在博客中寫道,為什么錯誤消息應該是“診斷但不是規定性的:描述問題,而不是解決方案”。 在這里閱讀

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM