2016-06-09 31 views
4

考慮下面的代碼:從`using`塊的方法返回時如何處理內存?

public Bar GetBar() 
{ 
    using(var foo = new Foo()) 
    { 
     return foo.Bar; 
    } 
} 

這是泄漏,或者是foo.Dispose()叫什麼名字?由於foo被丟棄,返回值是否可能是無效的?

+0

你在Bar實例的Foo類的Dispose方法中做了什麼? – Steve

+0

@Steve - 爲了討論起見,我們不確定;也許它會調用Bar.Dispose()或類似的東西。 – Conduit

+2

如果Foo.Dispose配置Bar,則不能在使用範圍外使用它。如果沒有,那麼你可以安全地使用Bar的引用。直到存在對Bar實例佔用的內存的引用。 – Steve

回答

3

這裏的答案很接近但不完整,不一致。

這是泄漏,還是foo.Dispose()調用?

Dispose被調用。 using塊被轉換爲try/finally塊,其中部分中的foo被處置。 finally將在try完成後(無論是通過例外還是自然)並在返回給調用者之前調用。所以Dispose將在幾乎所有情況下被調用(除非非常嚴重的例外,如超出內存,線程中止等)

是否有可能爲Foo的結果被設置的返回值是無效的?

當然,如果Dispose做一些事情無效是Bar引用,那麼是的,它肯定可以返回一個「無效」的參考對象。但那必須是明確Foo之內。處置對象不會自動處理所有屬性。

+0

我不知道使用'''嘗試...終於'轉換,並詳細的行爲[這裏](http://stackoverflow.com/questions/345091/will-code-in-a-finally-statement-fire-if-i-return-a-value-in-a- try-block/345270#345270)...儘管現在一切都很有意義 - 感謝大綱! – Conduit

2

這是泄漏

號這有利於編碼習慣幾乎實現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,則可能(取決於它如何更改),更改可能會傳出並使結果無效。

我想這個故事的寓意在於,如果你開始使用已經處理的對象進行遊戲,那麼經驗(或創建)各種奇怪的行爲,但這取決於處理對象在做什麼處置。我不會推薦它作爲一種做法,因爲大多數物體不打算在處理後使用。將你的「工作」作爲使用塊內的原子單元執行,然後讓對象死亡。

+1

'儘管它已被分配給一個已被處置的對象' - 而是'分配了'一個對象,我認爲如果我的英語服務器很好。雖然真的,我們不應該在外面使用foo進行廣告宣傳,因爲它是爲所有意圖和目的而設置的(通過'合同'制定,所以不應再使用它)。而且這也給人一種錯誤的印象。如果開發人員知道foo的詳細信息(或者信任它會以這種方式行事),那麼您在使用中返回一個「等號」,並且從使用中返回一個屬性,這是不正確的, 。 – NSGaga

相關問題