簡體   English   中英

C#如何實現Dispose方法

[英]C# how to implement Dispose method

我需要一些關於Dispose方法實現的建議。

在我們的應用程序中,用戶設計自己的UI。 我有一個預覽窗口,顯示UI的外觀。 在此UI中繪制的所有對象最終都來自公共基類ScreenObject。 我的預覽管理器包含對ScreenGrid的單個對象引用,ScreenGrid是整個預覽區域的網格對象。

問題#1

我的一些派生屏幕類保留在非托管資源上,例如數據庫連接,位圖圖像和WebBrowser控件。 這些類需要處理這些對象。 我在基本ScreenObject基類中創建了一個虛擬Dispose方法,然后在每個保存到非托管資源的派生類中實現了一個覆蓋Dispose方法。 但是,現在我剛剛創建了一個名為Dispose的方法,我沒有實現IDisposable 我應該實現IDisposable嗎? 如果是這樣,我該如何實現它?

  • 只是在具有非托管資源的派生類上
  • 基類和具有非托管資源派生類
  • 基類和所有派生類,包括那些沒有非托管資源的類

將虛擬Dispose方法放在沒有非托管資源的基類中是否錯誤,以便您可以利用多態?

問題2

在閱讀Dispose方法和IDisposable接口時,Microsoft聲明處置對象應該只為其父級調用Dispose方法。 父母將為其父母調用它,依此類推。 對我而言,這似乎是倒退。 我可能想要處理一個孩子但保留其父母。

我認為它應該是另一種方式,處置的對象應該處理它的孩子。 然后孩子們應該處理他們的孩子等等。

我錯在這里還是我錯過了什么?

問題1:使用以下模式實現IDisposable

public class MyClass : IDisposable
{
    bool disposed;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
        }
        //dispose unmanaged resources
        disposed = true;
    }

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

問題2:Microsoft的含義是派生類在其父類上調用dispose。 實例的所有者僅在最派生類型上調用Dispose。

一個(縮短的)例子:

class Parent : IDisposable 
{
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
        }
        //dispose unmanaged resources
        disposed = true;
    }

}
class Child : Parent, IDisposable 
{ 
    protected override void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                //dispose managed resources
            }
            base.Dispose(disposing);
        }
        //dispose unmanaged resources
        disposed = true;
    }

}
class Owner:IDisposable
{
    Child child = new Child();
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                if(child!=null)
                {
                    child.Dispose();
                }
            }
        }
        //dispose unmanaged ressources
        disposed = true;
    }
}

所有者只調用Child上的Dispose ,但不調用Parent。 Child負責在Parent上調用Dispose

問題1:

根據您列出的對象類型(即數據庫,WebBrowser,位圖等),就.NET而言,這些只是受資源。 因此,您應該在具有一次性類型作為成員的任何類上實現IDisposable 如果它們是本地聲明的實例,則只需對它們調用'using()'。 雖然你提到的這些實例確實有非托管資源,但是這些實際上是通過.NET從你使用的類型中抽象出來的。 由於您只使用托管類型,因此您應該實現IDisposable 但不使用終結器 如果您真的擁有非托管資源作為類成員,則只需要實現終結器。

問題2:

看來你將繼承(是a)與聚合/包含混淆(有一個)。 例如,如果“Container”包含一次性資源作為類成員,則稱為聚合/包含。 因此,在Container的IDisposable實現中調用base.Dispose()與在Container 內部處理一次性資源無關。 您應該記住,如果一個類派生自Container,比如說“DerivedContainer”,那么它 Container的一個實例,盡管有其他成員和/或功能。 因此,“DerivedContainer”的任何實例都具有其基類“Container”所具有的所有成員。 如果你從未調用過base.Dispose() ,那么“容器”中的可支配資源將無法正常釋放(它實際上是由GC實現的,但是由於很多原因,只是'讓.NET處理它'是不好的做法) -請參閱我發布的答案, 依賴.NET自動垃圾收集器是不好的做法?

如果你沒有調用基類Dispose() ,你最終會得到一個部分處理的對象(放置在派生類中但不在基類中) - 這是一個非常糟糕的場景。 因此調用基類Dispose()非常重要。

作為一個例子,我在我的博客上寫了一個我已經開發的最佳實踐模式(有很多經驗和調試內存轉儲)。 它展示了如何在基類和派生類上實現IDisposable

http://dave-black.blogspot.com/2011/03/how-do-you-properly-implement.html

我實現了IDisposable

 class ConnectionConfiguration:IDisposable
{
    private static volatile IConnection _rbMqconnection;
    private static readonly object ConnectionLock = new object();
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
        {
            return;
        }
        if (_rbMqconnection == null)
        {
            return;
        }
        lock (ConnectionLock)
        {
            if (_rbMqconnection == null)
            {
                return;
            }
            _rbMqconnection?.Dispose();//double check
            _rbMqconnection = null;
        }
    }
}

暫無
暫無

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

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