2012-08-03 187 views
1

我正在處理以下情況。我有一個基類有IDisposable模式,這意味着它有public virtual Dispose()方法和protected virtual Dispose(bool)方法。但是我無法在派生類中實現這個模式,所以我不會收到任何CA警告。請考慮下面的例子:在沒有CA警告的情況下執行Inhertited IDisposable模式

public class UtilizeClass : IDisposable 
{ 
    private MyData data; 

    public UtilizeClass() 
    { 
     data = new MyData(); 
    } 

    public void Dispose() 
    { 
     data.Dispose(); // Cannot use Dispose(bool) because it is protected. 
    } 
} 

public class MyData : Base, IDisposable 
{ 
    // Here we have some managed resources that must be disposed. 

    // How to implement the pattern? 
} 

public class Base : IDisposable 
{ 
    public virtual void Dispose() { } 
    protected virtual void Dispose(bool disposing) { } 
} 

一直以來我收到的MyData類矛盾CA警告。例如:刪除Dispose()並將其邏輯移動到Dispose(bool)。

非常感謝您的回答和幫助。

+0

你能展示更多'MyData'嗎? – 2012-08-03 12:40:52

+0

「Base」是你自己的班級,還是來自第三方的班級? – 2012-08-03 12:41:20

+0

您是否真的需要使用Dispose(bool)方法,通常只有在您確實需要釋放非託管資源時才需要這種方法。 – CodingGorilla 2012-08-03 12:44:16

回答

0

基類應該有一個public void Dispose()(非虛擬)調用Dispose(true)

派生類應該簡單地覆蓋protected virtual void Dispose(bool disposing)

2

如果Base是你自己的類,那麼不要實現這種反模式。

當一個類同時包含必須處理的託管資源(例如應該擁有它自己的Dispose的Stream對象)和非託管資源時,使用雙重處置(如果處置爲true,則爲false)必須清理。

這是一個壞主意。相反,您的所有課程都適合一個或兩個類別:

A.只有非託管資源的課程。理想的情況是隻有一個每個類:

public sealed class HandlesUnmanaged : IDisposable 
{ 
    private IntPtr _someUnmanagedHandleOfSomeKind; 
    public string DoSomething(string someParam) 
    { 
    // your useful code goes here; 
    // make it thin, non-virtual and likely to be inlined 
    // if you need to extend functionality, but it in a 
    // containing Disposable class, not a derived class. 
    } 
    private void CleanUp() 
    { 
    //your code that cleans-up someUnmanagedHandleOfSomeKind goes here 
    } 
    public void Dispose() 
    { 
    CleanUp(); 
    GC.SuppressFinalize(this);//finaliser not needed now. 
    } 
    ~HandlesUnmanaged()//not called if already disposed 
    { 
    CleanUp(); 
    } 
} 

理想情況下,你甚至不需要任何這樣的類,但使用SafeHandle這確實是給你的。

B.類,但需要處理的一個或多個管理的資源:

public class NoUnmanaged : IDisposable 
{ 
    private HandlesUnmanaged _likeAbove; 
    private Stream _anExampleDisposableClass; 
    public virtual void Dispose() 
    { 
    _likeAbove.Dispose(); 
    _anExampleDisposableClass.Dispose(); 
    } 
    /* Note no finaliser, if Dispose isn't called, then _likeAbove's 
    finaliser will be called anyway. All a finaliser here would do is 
    slow things up and possibly introduce bugs. 
    */ 
} 
public class DerivedNoUnManaged : NoUnmanaged 
{ 
    Stream _weMayOrMayNotHaveAnotherDisposableMember; 
    public override void Dispose() 
    { 
    //note we only need this because we have 
    //another disposable member. If not, we'd just inherit 
    //all we need. 
    base.Dispose(); 
    weMayOrMayNotHaveAnotherDisposableMember.Dispose(); 
    } 
} 

總之,我們既得到了簡單的非託管產階級是做同樣的事情在他們的Dispose()及其finaliser ,但前者呼叫GC.SuppressFinalize,或者我們擁有簡單的非非託管擁有課程,只需Dispose()他們需要處置的所有內容,包括必要時致電base.Dispose(),並且沒有終結者。沒有必要將邏輯分成同一類中的兩種類型。決賽者沒有風險調用已經敲定的東西,或者在定稿隊列中強制超過需要。

理想情況下,你甚至從來沒有做過第一種類型。只是第二種類型。

如果你不得不把它從另一個黨的類繼承,然後就去做:

public MyClass : Base 
{ 
    Stream _forExample; 
    public override void Dispose(bool disposing) 
    { 
    if(disposing) 
    { 
     _forExample.Dispose(); 
    } 
    base.Dispose(disposing); 
    } 
} 

自己不要處理disposing == false情況下,由於沒有混在裏面非託管資源。

+0

應該幾乎肯定只有一種虛擬處置方法。如果不希望有一個名爲'Dispose()'的公共方法,那麼虛擬方法幾乎肯定應該是'protected void Dispose(bool)',布爾實際上是一個虛擬參數來改變簽名。否則,有贊成使用無參數的'Dispose()'作爲虛擬清理方法的論據,或者讓它簡單鏈接到虛擬'Dispose(bool)'。由於只有直接持有非託管資源的類(而不是封裝它們的託管資源)是...... – supercat 2012-08-03 17:04:35

+0

......爲了實現這一目的而設計的那些類,不應期望'Dispose(false) 「除了記錄它被稱爲的東西以外,什麼都不做。順便說一下,非虛擬的'Dispose'應該可能調用'GC.SuppressFinalize()'。派生類不應該添加清理終結器,但可能會合法添加「警報」終結器。將'SuppressFinalize'放在非虛方法的末尾將確保它在所有派生類處置完成之後才能被調用。 – supercat 2012-08-03 17:05:45

+0

爲什麼不想要一個名爲'Dispose()'的公共方法?我可以看到的唯一影響是它使得班級的用戶更有可能不會意識到它是一次性的,因此不會處置它。 – 2012-08-03 22:38:28

相關問題