2015-12-13 76 views
-1

考慮下面的例子(代碼)。從Main函數進行到GetA的調用,該函數返回對函數GetA中創建的對象b的成員變量a的引用。請注意,在GetA返回後,我們不再有任何對本地變量b最初引用的對象的引用。然後我們通過致電GC.Collect()強制收集。引用成員變量 - 所有者不受GC支持?

我可以看到在Main方法的最後一行之前運行的B的終結代碼,這使我相信下面的代碼是不合格的?

問題:以下代碼格式不正確嗎?如果是這樣,即使對象被銷燬/收集,我們如何仍然可以訪問B類型的對象的成員a

using System; 

class A 
{ 
    public int x = 5; 
} 

class B 
{ 
    public A a = new A(); 

    ~B() 
    { 
     Console.WriteLine("Finalization code running for B."); 
    } 
} 

class Program 
{ 
    static A GetA() 
    { 
     B b = new B(); // <- Allocate object of type B on the managed heap 
     return b.a; // <- We return a (copy-of) reference to a member of B 
    } 

    static void Main(string[] args) 
    { 
     A a = GetA(); 

     // Force a garbage collection 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 

     // This works fine, but is this valid code? 
     // "Owner of" a (object of type B allocated in GetA) is dead! 
     Console.WriteLine("a.x = {0}", a.x); 
    } 
} 
+0

「不健康」你是什麼意思?一個錯誤? .NET沒有像C一樣的未定義行爲。任何情況下都不能訪問「無效」對象。 – usr

+0

是的,我的意思是錯誤。如果我運氣好的話,GC還沒有運行,如果我運氣不好,GC已經運行。 – jensa

+2

出於同樣的原因,我們有哈姆雷特,即使威廉莎士比亞早已被死亡率的偉大GC收集。 –

回答

1

我們爲什麼仍然有機會獲得A B

類型的對象,我們不必B.a訪問的成員。我們可以訪問過去被B.a引用的對象。

GetA中創建的B實例創建了A的新實例,並在B.a字段中存儲了對該實例的引用。這個A的實例是一個單獨的對象,只要它可到達,它就不會被收集。

+0

謝謝,這解釋了一切。 – jensa