2012-10-12 46 views
2

我有一些關於一次性類的問題。假設我有一個IDisposable實現類有一些一次性成員。我已經實現了Dispose()方法,即:一次性成員從一次性類派生的類

class BaseCustom: IDisposable 
{ 
    private System.Net.Sockets.TcpClient tc; 
    private System.Net.Sockets.NetworkStream ns; 
    public string str; 
    public int i; 

    public BaseCustom(string host, int port) 
    { 
     tc = new System.Net.Sockets.TcpClient(host, port); 
     ns = tc.GetStream(); 
    } 

    // some other methods work on members (i, str, tc, ns) 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      if (ns != null) 
      { 
       ns.Close(); 
       ns = null; 
      } 
      if (tc != null) 
      { 
       tc.Close(); 
       tc = null; 
      } 
     } 
    } 

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

Q1)由於沒有非託管資源,是確定surpress終結? (在代碼閱讀note這裏)

Q2)由於我們處理一次性成員和抑制GC,會發生什麼在這裏intstring成員?我們還需要處理它們嗎?

Q3)當前是否空出tcns是否正確?我看到不同版本的.NET引用內部的分歧有關調用Close()Dispose()

現在假設我們有一個派生類:

class DerivedCustom : BaseCustom 
{ 
    public string cstr; 
    public int ci; 

    public DerivedCustom(string host, int port) 
     : base(host, port) 
    {} 

    // some extra methods 
} 

Q4)可能與Q2;我們是否需要在這裏覆蓋任何Dispose()?我們不會在派生類中引入任何非託管或可支配資源。是否可以保持原樣(即信任基地的處置機制)?如果GC被抑制(在派生過程中被抑制,右),cicstr會發生什麼?也與Q1有關,我們是否需要任何終結者?

Q5)如果底座是抽象類,該怎麼辦?

Q6)這很有趣;該代碼不會給出有關FxCop 1.36中的可處置性的任何警告。但是,如果我一次性成員添加到DerivedCustom仍然不會覆蓋一次性使用方法(因此不處理新成員),如:

class DerivedCustom : BaseCustom 
{ 
    public string cstr; 
    public int ci; 
    // below is the only extra line 
    public System.Net.Sockets.TcpClient ctc = new System.Net.Sockets.TcpClient("ho.st", 1234); 

    public DerivedCustom(string host, int port) 
     : base(host, port) 
    {} 

    // some extra methods 
} 

仍然沒有得到任何的FxCop警告。這有點讓我感到驚訝,因爲ctc的處置似乎沒有妥善處理。

回答

2

A1)如果沒有非託管資源,請不要爲該類添加終結器。終結器對於清理非託管資源非常有用; GC將自行處理管理資源。

A2)SuppressFinalize不會阻止對象被垃圾收集;它只會阻止GC調用對象的終結器。因爲它們是值類型,所以無箱裝入的數據從不會被垃圾回收。字符串將像往常一樣被垃圾收集。 A3)我會調用Dispose而不是Close,因爲Dispose保證有Dispose語義,而Close可能會做些稍微不同的事情。

A4)如果派生類沒有添加新的處置要求,請勿重寫Dispose方法。 A5)如果基地是一個抽象類,它不會產生影響。

A6)我不太瞭解FXCop的回答,抱歉。

此外,沒有理由將字段設置爲空。例如,在沒有非託管資源的情況下,Dispose方法應該如下所示(編輯:重新閱讀鏈接到問題的FXCop頁面,我會補充說在這種情況下該類應該被密封):

public void Dispose() 
{ 
    if (ns != null) 
    { 
     ns.Dispose(); 
    } 
    if (tc != null) 
    { 
     tc.Dispose(); 
    } 
} 

但是,如果類可能有持有非託管資源派生型,但是,你應該用經典花紋棒,從你的榜樣一些修改:

protected virtual void Dispose(bool disposing)   
{   
    if (disposing)   
    {   
     if (ns != null)   
     {   
      ns.Dispose();   
     }   
     if (tc != null)   
     {   
      tc.Dispose();   
     }   
    }   
}   

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

+1。所有優秀的答案。不過,我會澄清,因爲int是值類型,當它們駐留的對象被垃圾收集時,它們消耗的空間會自動刪除。 – StriplingWarrior

+0

關於A5,也不需要檢查它們是否爲空 - 構造函數將確保它們被設置。只需在沒有檢查或分配的情況下連續運行Dispose()。 –

+0

@ JesseC.Slicer好點,但它可能是一個很好的習慣,因爲這只是* this *類的不變性;在其他情況下,可能需要空檢查。 – phoog

0

Q1:是的。

Q2:不,他們是100%託管類型,GC會照顧他們。 IDisposable適用於繼承或組合中某處的類型,需要處理非託管資源。如tcns

Q3:致電Dispose()。這是慣用的,一個很好的實現將被稱爲它自己的Close()

Q4:不,不需要覆蓋。無處抑制GC - 因爲您已經運行Dispose(),所以您禁止運行終結器的GC。

Q5:與Q4沒有什麼區別。

Q6:是的,FxCop在其規則IDisposable中有誤報和漏報。遵循最佳實踐並忽略FxCop中似乎有些魚腥味,你會沒事的。

0

你應該考慮在實現IDisposable接口的基類中實現終結器(Dispose Pattern)。

IDisposable接口用於釋放原生資源。 Int32String由GC進行資源管理和收集。

如果基類是抽象類或具體類,如果該類使用非託管/本地資源,則無關緊要。

即使派生類沒有定義任何新資源,但該類仍繼承基類功能,這意味着派生類對象將使用本機資源。即使您在派生類中跳過聲明終結器,但終止器已在基類中定義,基類終結器也足以指示GC在內存收集期間運行終結器。

確實(實際上必須)調用GC.SuppressFinalize,因爲它從F-Reachable隊列中刪除條目並幫助GC在第一次掃描中收集對象內存。

相關問題