2010-01-04 43 views
9

我對堆棧和堆在類中的值類型屬性方面發生了什麼感到困惑。從屬性返回值類型

我的理解至今:

當您創建這樣一個結構(值類型)類:如果你創建一個類的實例,像這樣

class Foo 
{ 
    private Bar _BarStruct; 
    public Bar BarStruct 
    { 
    get {return _BarStruct; } 
    set {_BarStruct = value; } 
    } 
} 

private struct Bar 
{ 
    public int Number; 
    Bar() 
    { 
    Number = 1; 
    } 
    Bar(int i) 
    { 
    Number = i; 
    } 
} 

Foo fooObj = new Foo(); 

堆棧和堆將如下所示:

https://i962.photobucket.com/albums/ae105/acardy/stackheap-1.jpg(https://i962.photobucket.com/albums/ae105/acardy/stackheap-1.jpg)

...其中Bar結構嵌入在堆中的Foo類中。這對我來說很有意義,但是當我們考慮在Foo對象中修改BarStruct類中的Number整數時,我開始鬆開它。例如:

Foo fooObj = new Foo(); 
fooObj.BarStruct.Number = 1; 

據我所知,這應該返回BarStruct副本住堆棧,這意味着BarStruct成員的任何更改將不通過攜帶的對象,這也就是爲什麼在上面的最後一行給出了一個錯誤。

這是正確的嗎?

如果是這樣,我的問題是,如何分配來像這樣:

fooObj.BarStruct = new Bar(2); 

...是有效的,並且改變堆價值?當然,這只是改變了堆棧上的值?另外,(通過和)我覺得你很容易使用新的值類型。對我來說,新增功能是針對堆(按照C++)進行分配,並且對堆棧中的項目執行此操作感覺不自然。

所以,只是爲了重新提出這個問題,我是否正確地假設當調用包含結構的屬性時會發生什麼,以及爲什麼可以將新結構指定給副本,但它仍然會更改堆?

真的希望這一切都有道理。

大喊,如果你需要澄清!

Ta,

Andy。

+0

@Andy,+1個不錯的問題。如果你問10位經驗豐富的C#程序員,我敢打賭,不到一半的人會知道這裏發生了什麼。結構很棘手,因爲它們看起來像類,但它們有重要的區別。 – Ash 2010-01-14 07:12:31

回答

10

看着這個任務:

fooObj.BarStruct = new Bar(2); 

的分配是不是在堆棧上改變價值 - 它調用該屬性的二傳手

換句話說,而你的第一項任務是等價於:

fooObj.get_BarStruct().Number = 1; // Bad 

第二等同於:

fooObj.set_BarStruct(new Bar(2)); 

這是否幫助?

請注意,如果您將您的值類型設置爲不可變,那麼有問題的賦值就成爲一個非問題 - 事實上,這對一般情況有幫助。在C#中,可變值類型是一個非常糟糕的主意;你可以與他們解決問題。

根據你對「新」的期望 - 儘量不要用C++思考,基本上。 C#不是C++,如果您嘗試在C#中有效編寫C++,各種各樣的東西(析構函數,泛型,構造期間的行爲)都會讓您感到困惑。 「新」語句創建一個類型的新實例,無論是值類型還是引用類型。

+0

其實,這確實有很大的幫助,實際上我應該想到,雖然這在邏輯上有點多,但希望它也可以幫助其他人! :) 非常感謝! – Andy 2010-01-04 13:36:58

+0

Jon,當我嘗試將它們包裝在proerties中時,我剛剛使用了System.Drawing.Rectangle和System.Drawing.Point。微軟真的應該讓這些結構不可變。 – Ash 2010-01-14 07:15:09

+0

@Ash:我同意。可變結構可以用於*非常有限的一些情況,但它們幾乎總是比有益的更危險。 – 2010-01-14 07:48:11