2010-02-17 47 views
30

Dispose()方法中將自定義對象設置爲null(在VB.NET中爲Nothing)有什麼意義嗎? 這可以防止內存泄漏或它沒用??在Dispose()中設置obj = null(Nothing)的任何意義?

讓我們來看兩個例子:

public class Foo : IDisposable 
{ 
    private Bar bar; // standard custom .NET object 

    public Foo(Bar bar) { 
     this.bar = bar; 
    } 
    public void Dispose() { 
     bar = null; // any sense? 
    } 
} 

public class Foo : RichTextBox 
{ 
    // this could be also: GDI+, TCP socket, SQl Connection, other "heavy" object 
    private Bitmap backImage; 

    public Foo(Bitmap backImage) { 
     this.backImage = backImage; 
    } 

    protected override void Dispose(bool disposing) { 
     if (disposing) { 
      backImage = null; // any sense? 
     } 
    } 
} 

回答

19

Dispose()的目的是爲了讓清理不是由垃圾收集處理的資源。對象由GC處理,所以在正常情況下,實際上不需要將引用設置爲null。

例外情況是,如果您希望主叫方呼叫Dispose之後保留該實例。在這種情況下,將內部引用設置爲null可能是一個好主意。但是,一次性實例通常是同時處置和釋放的。在這些情況下,它不會產生很大的影響。

+0

在我的第二個例子中,我有一個位圖,建議Dispose()。現在,由於位圖不是由對象Foo創建的,而是剛剛通過參數傳遞的,所以我不能這樣做。我認爲至少將它設置爲空... – serhio 2010-02-17 11:13:19

+4

你總是需要決定清理依賴關係的地方。如果你知道位圖沒有在其他地方使用,Foo應該調用Dispose()。否則,它應該離開它,並讓來電者處理清理。 將本地引用設置爲null沒有其他好處。當Foo的實例被回收時,除非調用者仍然持有對它的引用,否則是Bitmap的實例。 – 2010-02-17 11:18:01

+2

@serhio - 如果你想釋放你的Bitmap對象使用的資源,只要你在Foo中使用它(沒有其他人正在使用它),那麼Foo.Dispose應該調用backImage.Dispose – Gishu 2010-02-17 11:19:38

0

dispose()的目的是清理不受管理的資源。 TCP連接,數據庫連接和其他數據庫對象以及許多這樣的非託管資源應該由開發人員在dispose方法中發佈。所以這真的很有意義。

+0

這兩個示例與GDI +位圖和一個簡單的自定義.NET對象欄?我不處理它們,導致參數傳入,而不是由對象創建。 – serhio 2010-02-17 11:15:55

23

我個人傾向於;原因有二:

  • 這意味着,如果有人忘了(從事件也許)釋放Foo任何下游對象(在這種情況下,Bitmap)仍然可以收集(在將來的某個時候 - 無論何時GC感覺像是這樣);它可能是,這只是一個非託管資源的淺層包裝,但每一點都有幫助。
    • 我真的不喜歡意外地保持一個完整的對象圖掛在僅僅因爲用戶忘記解開一個事件; IDisposable是一個方便的「幾乎殺死」開關 - 爲什麼不分離一切可用?
  • 更重要的是,我可以厚着臉皮現在使用這個字段來檢查(在方法等)進行處置,拋出ObjectDisposedException如果是null
+1

在對它們調用Dispose()之後,你多久保持對對象的引用? – 2010-02-17 11:23:37

+8

@Brian - 注意「意外」和「事件」等字樣;並注意**我**不一定是編寫*使用*我的組件的代碼的人。我無法修復*他們的*代碼,但我可以讓我的行爲良好。 – 2010-02-17 11:24:28

+0

@Dave - 澄清 – 2010-02-17 11:26:36

4

它只是無用的。在舊的COM/VB日期中設置爲NULL,我相信會減少引用計數。

這不適用於.NET。當你將bar設置爲null時,你不會銷燬或釋放任何東西。您只需將對象指向的內容從對象改爲「null」即可。你的對象仍然存在(儘管現在,因爲沒有指向它,它最終將被垃圾收集)。除了少數例外情況,並且在大多數情況下,如果您沒有首先製作Foo IDisposable,就會發生同樣的情況。

IDisposable的主要目的是允許您發佈非託管資源,如TCP套接字或SQL連接,或其他。這通常通過調用非託管資源提供的清理函數來完成,而不是通過將引用設置爲「null」來完成。

+1

好的,如果改爲* Bar *我有* TCP套接字*?它應該是無用的,將其設置爲空?導致它通過參數傳遞,「有人」可以使用這個對象... – serhio 2010-02-17 11:27:05

+1

是的,這將是無用的。如果你有一個TCP套接字,你可以通過調用套接字的.Close()方法釋放它。與SQL連接一樣。設置爲「null」實際上只會改變對正在使用的對象的引用。 – 2010-02-17 11:49:38

+1

-1,設置爲無,允許垃圾收集器在第一遍時清理。 – AMissico 2010-03-12 01:36:24

1

如果您想以某種方式防止處置的擁有實例被重新使用,這可能是有意義的。

當您將一次性字段的引用設置爲空時,將保證不再使用這些實例。

您將不會得到ObjectDisposedException或由於使用擁有的處置實例而導致的任何其他無效狀態(如果不檢查空值,可能會得到NullReferenceException)。

這可能沒有什麼意義,你只要所有IDisposable對象有IsDisposed財產和/或拋出ObjectDisposedException如果它們被佈置後,他們使用 - 一些可能違反這一原則,將其設置爲空可避免不必要的影響發生的歷史。

1

在C#中將對象設置爲null只是釋放對象的引用。

因此,從理論上講,在C#中的Dispose-Method中釋放託管對象的引用是更好的做法,但僅限於GC在收集處置對象之前收集引用對象的可能性。由於兩者很可能在同一次運行中收集,因此GC將最合理地認識到,所引用的對象僅由一種處置類型引用,因此兩者都可以收集。

此外,釋放引用的需求也非常小,因爲如果類是alreay處置,則您的一次性類的所有公共成員都應該拋出異常。因此,在處理引用的方法後,不會訪問您的引用對象。

+0

Thx Dave,更改了有關VB.NET的信息 – 2010-02-17 11:56:48

+0

因此,設置Nothing時C#和VB.NET有什麼區別?我在C#中提出了可讀性方面的問題,但我的真實項目是在VB.NET中。 – serhio 2010-02-17 11:58:29

+2

爲了您的目的,沒有區別。但VB.NET是一種可怕的語言。在VB.NET中,如果將Dim x設置爲integer = Nothing,然後輸出「x」的值,則得到0.在C#中,它只是不編譯,因爲「int」是一個值類型,「null」是嚴格的參考。所以他們的表現不完全一樣。但對於像IDisposable對象這樣的引用類型,它們的行爲方式完全相同。 – 2010-02-17 12:06:31

1

VB.NET是感設置爲Nothing宣佈Private WithEvents對象。

使用Handles關鍵字的處理程序將以這種方式從這些對象中移除。

0

一般不需要設置爲空。但是,假設你在課堂上有重置功能。

然後你可能會這樣做,因爲你不想調用兩次配置,因爲一些Dispose可能沒有正確實現並拋出System.ObjectDisposed異常。

private void Reset() 
{ 
    if(_dataset != null) 
    { 
     _dataset.Dispose(); 
     _dataset = null; 
    } 
    //..More such member variables like oracle connection etc. _oraConnection 
} 
相關問題