2010-07-22 55 views
1

我有這個類:在這種情況下,Dispose()會提前釋放資源嗎?

class Foo : IDisposable 
{ 
    SomeBigResource resource; 

    void UsingResource() 
    { 
    using(Bar bar = new Bar(SomeBigResource) 
     bar.doStuff(); 
    } 

    void Dispose() 
    { 
    resource.Dispose(); 
    } 
} 

void Function() 
{ 
    using (Foo foo = new Foo(new SomeBigResource)) 
    foo.UsingResource(); 
} 

酒吧對象具有完全相同的Dispose()功能。
我的SomeBigResource會被釋放還是GC智能足以在第二次使用完成後再釋放它?

+4

Dispose與GC無關。 – 2010-07-22 14:12:15

+0

SomeBigResource所屬的類必須配置它 – Arseny 2010-07-22 14:19:30

回答

4

如果Dispose方法無論是在FooBar電話DisposeSomeBigResource對象上,該方法將被調用兩次。如果方法正確實施,它將首次釋放資源,第二次不做任何事情。

你有什麼是責任混淆,兩個對象負責在SomeBigResource對象上調用Dispose。這是你想避免的,因爲一個對象不知道另一個對象是否仍然需要這個資源,所以你只想把責任放在一個地方。

您應該使Foo對象負責資源的生命週期,或者完全在對象之外處理它。後者更有意義,因爲這是您創建實例的地方:

using (SomeBigResource resource = new SomeBigResource()) { 
    using (Foo foo = new Foo(resource)) { 
    foo.UsingResource(); 
    } 
} 
2

您的資源將被丟棄兩次。

GC完全不知道IDisposable s和using聲明。

將每個using聲明翻譯成try/finally塊,並在finally塊中調用Dispose()
這是一個常規的方法調用,它將始終執行。

因此,在UsingResource()using語句將配置資源,然後在Function()using聲明再次將其丟棄。

全部IDisposable實現應該是冪等的(第二次調用應該沒有危害)。因此,(假設SomeBigResource正確地實現了IDisposable),你的代碼應該可以正常工作。

但請注意,在您的班級中,一個空的using區塊會拋出NullReferenceException,這是非常錯誤的。
您應該在Dispose方法中添加一個null支票。

+0

所以基本上我應該刪除UsingResource()中的使用? – 2010-07-22 14:14:58

+0

實際上,您應該刪除該字段並將其設爲私有變量。 – SLaks 2010-07-22 14:16:46

+1

@the_drow,我會圍繞'SomeBigResource'實例包裝'using',而不是依賴於那個實例的對象。如果他們沒有創建它,'Foo'和'Bar'不應該負責清理'SomeBigResource'。 – 2010-07-22 14:17:27

2

這取決於執行Bar.Dispose()。假設它具有與Foo類似的實現方式,那麼,是的,發佈會提前發生。

看看Dispose pattern guidancethis SO question。你可能會想到更多的角落案例。

2

我想這行應爲:

using(Bar bar = new Bar(resource)) 

如果在bar佈置是這樣的話,那麼,它應該處置resource

所以,是的。當bar配置在UsingResource中時,它將配置resource,這樣如果您稍後嘗試使用它,則應該會拋出ObjectDisposedException。 (雖然你簡單的例子,這是不應該的。)