簡體   English   中英

處理IDisposable的最佳實踐

[英]Best practices for handling IDisposable

我有一個類層次結構,每個成員可以創建IDisposable對象。

我將List<IDisposable>屬性添加到此層次結構中的基類,我在創建時向其添加任何一次性對象。 Dispose方法遍歷此列表並為其列表中的每個項調用Dispose並清除列表。 在應用程序中,我顯式調用頂級對象的Dispose方法,導致處理級聯層次結構。

這有效,但還有更好的方法嗎? 我是否無意中重復了框架中已有的某些功能?

(注意 - 有問題的對象的生命周期不能將它們包裝在一個using塊中,或者在創建它們的同一個using處理它們。)

編輯

只是為了澄清 - 我只是保留那些需要保留的物體。 有些是在創建它們的同一方法中處理掉的,但是很多都以這種方式使用,這是不可能的。

不,這是正確的。 IDisposable旨在釋放非托管資源,應在完成實例后盡快調用。 這是一種常見的誤解,認為這是不必要的,或者當對象被垃圾收集時,finailizer會自動執行此操作。 它不是。

IDisposable的正確模式在這里 ,包含在下面以供快速參考。

public class Resource : IDisposable 
{
    // Dispose() calls Dispose(true)
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // NOTE: Leave out the finalizer altogether if this class doesn't 
    // own unmanaged resources itself, but leave the other methods
    // exactly as they are. 
    ~Resource() 
    {
        // Finalizer calls Dispose(false)
        Dispose(false);
    }

    // The bulk of the clean-up code is implemented in Dispose(bool)
    protected virtual void Dispose(bool disposing)
    {
        if (disposing) 
        {
            // free managed resources
        }
        // free native resources here if there are any
    }
}

只要你正確地實現一次性的圖案(如描述在這里 ),這個方法是好的。

據我所知,只有using語句才能對IDisposable提供特殊支持 - 框架中沒有任何東西可以復制你正在做的事情。

如果你在談論任意IDisposable對象,我不相信它存在。

System.ComponentModel.Container類實現級聯Dispose,但要求元素實現IComponent 如果您控制IDisposable對象,您可以使它們實現IComponent - 它只需要實現一個可以返回null屬性Site

聽起來像訪客模式可能合適的情況。 雖然我從來沒有理解它擴展你的類並使它們保持不變的說法,因為我只知道類應該有AcceptVisitor方法等的例子。 順便說一句,這不是我喜歡的模式,因為它很復雜並且往往會使代碼混亂。

如果一個對象將創建許多其他IDisposable對象並在其存在期間保持對它們的所有權,那么您描述的模式可能是一個好的。 可以通過讓你的類實現方法“T RegDispos <T>(T thing)T:IDisposable”來增強它; 這將在列表中添加一次性並返回。 因此,可以通過替換諸如“someField = someDisposType.CreateThing();”之類的語句來處理同一語句中的資源的創建和清理。 with“someField = RegDispos(someDisposType.CreateThing());”。

如果你的類沒有公開一個公共構造函數(需要外人使用工廠方法),如果你要么使用vb.net或者願意使用線程靜態字段,你甚至可以將初始化和清理與聲明結合起來(例如“ var someField = RegDispos(someDisposType.CreateThing());“)。 為了安全起見,必須在try / catch或try / finally塊中調用構造函數,如果構造失敗,可以在創建的子對象上調用Dispose。 因為C#中的字段初始化器無法訪問構造函數參數(語言中的弱點,恕我直言),實現這種模式的唯一方法是讓工廠方法創建列表並將其放入線程靜態變量中然后通過靜態RegDispos方法讀取。

暫無
暫無

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

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