考慮下面的代碼:從`using`塊的方法返回時如何處理內存?
public Bar GetBar()
{
using(var foo = new Foo())
{
return foo.Bar;
}
}
這是泄漏,或者是foo.Dispose()
叫什麼名字?由於foo
被丟棄,返回值是否可能是無效的?
考慮下面的代碼:從`using`塊的方法返回時如何處理內存?
public Bar GetBar()
{
using(var foo = new Foo())
{
return foo.Bar;
}
}
這是泄漏,或者是foo.Dispose()
叫什麼名字?由於foo
被丟棄,返回值是否可能是無效的?
這裏的答案很接近但不完整,不一致。
這是泄漏,還是foo.Dispose()調用?
Dispose
被調用。 using
塊被轉換爲try
/finally
塊,其中部分中的foo
被處置。 finally
將在try
完成後(無論是通過例外還是自然)並在返回給調用者之前調用。所以Dispose
將在幾乎所有情況下被調用(除非非常嚴重的例外,如超出內存,線程中止等)
是否有可能爲Foo的結果被設置的返回值是無效的?
當然,如果Dispose
做一些事情無效是Bar
引用,那麼是的,它肯定可以返回一個「無效」的參考對象。但那必須是明確在Foo
之內。處置對象不會自動處理所有屬性。
我不知道使用'''嘗試...終於'轉換,並詳細的行爲[這裏](http://stackoverflow.com/questions/345091/will-code-in-a-finally-statement-fire-if-i-return-a-value-in-a- try-block/345270#345270)...儘管現在一切都很有意義 - 感謝大綱! – Conduit
這是泄漏
號這有利於編碼習慣幾乎實現IDisposable的,因爲它可確保在「拿來主義」的變量被熄滅Dispose方法被立即調用的任何對象範圍(例如代碼離開使用塊)。有一些例外(WCF客戶端,自定義代碼不遵循良好的IDisposable實踐),但將任何IDisposable包裝在使用塊中是一個好主意,除非您有特定的理由不要。
是否有可能爲Foo的結果被設置
這取決於什麼Foo中的Dispose
方法不返回值是無效的。例如,如果您嘗試調用引用已關閉/處置的SQLConnection的SQLCommand,則會收到異常。讓我們看一個讓這個行爲變得明顯的例子。
public class Foo : IDisposable
{
public Foo()
{
ComplexType = new ComplexType();
}
public ComplexType ComplexType { get; set; }
public void Dispose()
{
ComplexType = null;
GC.Collect();
}
}
現在這一段代碼,訪問我們的美孚:
static void Main(string[] args)
{
Foo foo;
ComplexType complexType;
using (var newFoo = new Foo())
{
foo = newFoo;
complexType = newFoo.ComplexType;
}
Console.WriteLine(complexType.SomeProperty); // This works :)
Console.WriteLine(foo.ComplexType.SomeProperty); // Throws an exception because ComplexType is NULL
Console.ReadKey();
}
奇怪吧?發生這種情況的原因是因爲在Foo構造函數中,我們創建一個新的ComplexType並將其存儲在內存地址中。 Foo.ComplexType屬性包含參考到內存地址。當我們調用dispose時,我們將引用設置爲null,但實際的對象不是垃圾回收,因爲我們在調用代碼中有其他引用,所以我們無法通過foo.ComplexType
屬性訪問它,但它是仍可通過complexType
變量訪問。另請注意,foo
即使已分配給已處理的對象也不爲null。因爲我們的Foo
實例仍然存在引用,儘管位於使用塊之外,但它仍然存在,因爲在引用存在時無法收集它。
現在,如果Dispose
方法更改了SomeProperty,則可能(取決於它如何更改),更改可能會傳出並使結果無效。
我想這個故事的寓意在於,如果你開始使用已經處理的對象進行遊戲,那麼經驗(或創建)各種奇怪的行爲,但這取決於處理對象在做什麼處置。我不會推薦它作爲一種做法,因爲大多數物體不打算在處理後使用。將你的「工作」作爲使用塊內的原子單元執行,然後讓對象死亡。
'儘管它已被分配給一個已被處置的對象' - 而是'分配了'一個對象,我認爲如果我的英語服務器很好。雖然真的,我們不應該在外面使用foo進行廣告宣傳,因爲它是爲所有意圖和目的而設置的(通過'合同'制定,所以不應再使用它)。而且這也給人一種錯誤的印象。如果開發人員知道foo的詳細信息(或者信任它會以這種方式行事),那麼您在使用中返回一個「等號」,並且從使用中返回一個屬性,這是不正確的, 。 – NSGaga
你在Bar實例的Foo類的Dispose方法中做了什麼? – Steve
@Steve - 爲了討論起見,我們不確定;也許它會調用Bar.Dispose()或類似的東西。 – Conduit
如果Foo.Dispose配置Bar,則不能在使用範圍外使用它。如果沒有,那麼你可以安全地使用Bar的引用。直到存在對Bar實例佔用的內存的引用。 – Steve