2010-02-13 52 views
4

以下代碼是否使using(...)功能/用途無關?
是否會導致GC性能不足?使用`使用(...)`有效無效和/或效率低下?

class Program 
{ 
    static Dictionary<string , DisposableClass> Disposables 
    { 
     get 
     { 
      if (disposables == null) 
       disposables = new Dictionary<string , DisposableClass>(); 

      return disposables; 
     } 
    } 

    static Dictionary<string , DisposableClass> disposables; 

    static void Main(string[] args) 
    { 
     DisposableClass disposable; 
     using (disposable = new DisposableClass()) 
     { 
      // do some work 
      disposable.Name = "SuperDisposable"; 
      Disposables["uniqueID" + Disposables.Count] = disposable; 
     } 

     Console.WriteLine("Output: " + Disposables["uniqueID0"].Name); 

     Console.ReadLine(); 
    } 
} 

class DisposableClass : IDisposable 
{ 
    internal string Name 
    { 
     get { return myName; } 
     set { myName = value; } 
    } 

    private string myName; 

    public void Dispose() 
    { 
     //throw new NotImplementedException(); 
    } 
} 

輸出:SuperDisposable

我的using(...)功能的理解是立即強制處置DisposableClass的。然而,在代碼塊中,我們將該類添加到字典集合中。我的理解是,一個類本質上是一個參考類型。所以我的實驗是看看以這種方式添加到集合中的一次性對象會發生什麼。

在這種情況下DisposableClass仍然很活躍。類是一個引用類型 - 所以我的假設變成了這個集合不是簡單地引用這個類型,而是確實把類作爲一個值。但是,這也沒有意義。

那麼究竟發生了什麼?

編輯:修改後的代碼與輸出,以證明對象沒有死,可能會提出一些答案。

2日編輯:這是什麼歸結爲我通過一些更多的代碼去是這樣的:

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

    private void Dispose(bool dispose) 
    { 
     if (!isDisposed) 
     { 
      if (dispose) 
      { 
       // clean up managed objects 
      } 

      // clean up unmanaged objects 
      isDisposed = true; 
     } 
    } 

    ~DisposableClass() 
    { Dispose(false); } 

逐步執行代碼(曾在private void Dispose(bool dispose)斷點),其中false傳遞給方法,資源在這裏得到妥善處理變得勢在必行。無論如何,這個班還活着,但你絕對是爲了例外而設。答案讓我更加好奇......

回答

11

處置對象不會破壞它;它只是告訴它清理它使用的所有非託管資源,因爲它們不再需要。在你的例子中,你正在創建一個可處理的對象,分配給一個字典,然後告訴它去除一些資源。

using聲明的正確方案是當您要初始化資源,對它做某些事情,然後銷燬它並忘記它;例如:

using (var stream = new FileStream("some-file.txt")) 
using (var reader = new StreamReader(stream)) 
{ 
    Console.Write(reader.ReadToEnd()); 
} 

如果你想保留的對象,你用過之後,你不應該配置它,因此不應該使用using聲明。

+0

不夠公平。我試圖理解發生的事情。如果該對象被假定被丟棄,或與該對象相關的資源。 +1 – IAbstract 2010-02-13 23:27:55

2

你不應該在這種情況下使用using塊,因爲你所需要的對象塊結束後。只有當對象的生命週期有明確的起點和終點時才能使用它。

1

IDisposable接口指示型管理某種資源。該Dispose方法存在是爲了讓你處置由一個實例使用的資源,而不必等待垃圾回收發生和資源,由一個終結釋放。

在您的示例中,字典仍包含對可丟棄類的引用,但實例將在using塊的末尾處理。後續嘗試調用實例上的方法現在可能會拋出ObjectDisposedExceptionInvalidOperationException,以指示實例不再處於「工作」狀態。

處理IDisposable不會與釋放佔用該實例的內存或調用任何垃圾收集例程相混淆。實例由垃圾收集器跟蹤和管理,只在垃圾收集器決定它時才被釋放。

+0

@編程英雄:第二段是部分正確的......它取決於資源的正確處置,以及是否有任何班級成員使用這些處置的資源。它似乎仍然是一個奇怪的行爲。如果你編輯它,我會刪除倒票。 ;) – IAbstract 2010-02-13 23:54:26

+0

處置實例的行爲在很大程度上是未定義的;期望的是假設一個實例一旦處置就不再正常運行,因爲它所依賴的一些資源已經被釋放。很可能某些屬性仍會正常返回值,但大多數方法應該會失敗。 – 2010-02-14 21:37:02

2

重要的是要記住,IDisposable雖然是一個稍微特殊的接口,但它仍然是一個接口。當使用塊退出時,它會在您的對象上調用Dispose()。而已。你的引用仍然有效,如果你的Dispose方法什麼都不做,你的對象將完全不受影響。如果你沒有跟蹤處理並明確地拋出異常,那麼在這之後你將不會得到任何異常,因爲在.NET中沒有固有的處置狀態。

+0

+1 @尼克:關於「IDispose」的好處。 – IAbstract 2010-02-14 00:04:04