2017-07-13 14 views
0

我有這樣一本字典:如果我從字典中創建列表,並且如果從列表的對象中更改屬性,它會顯示在字典中嗎?

private Dictionary<string, TestObject> example = new Dictionary<string, TestObject>() { 
      { "object1", new TestObject()}, 
      { "object2", new TestObject()} 
     }; 

和我做一個清單:

internal List<TestObject> exampleList = example.Values.Where(x => x != null).Select(a => a).ToList(); 

的TestObject是這樣

class TestObject{ 
    string name = "phil"; 
    public void SetName(string name){ 
      this.name = name; 
    } 
} 

所以,如果我做這樣的事情:

foreach(TestObject object in exampleList){ 
    object.SetName("Arthur"); 
} 

這個值也會在字典中改變嗎?

+3

試試看! – frozen

+1

是的,在這裏你有小提琴https://dotnetfiddle.net/hBulTe的生動的例子,玩弄和檢查結果 –

回答

3

TestObject是一類 - 所以它是一個參考類型。當你從字典創建列表時,你只需傳遞對堆中對象的引用(你可以將引用看作鏈接)。你沒有在這裏傳遞對象。即使字典不包含對象 - 它只包含對象的引用。你可以有許多指向同一個對象的引用。你可以通過任何引用修改對象。但是對象只有一個。

這個值也會在字典中改變嗎?

是的,它會的。下面的圖片解釋了爲什麼

enter image description here

正如你可以看到在堆棧上,字典,列表和@object變量 - 在堆(三封推薦信)所有參考相同的TestObject實例。如果您將使用任何引用來修改TestObject名稱,那麼它將更新單個TestObject實例。

請注意,詞典Entry是一個結構(值類型),因此它的值直接存儲在數組中,而不是存儲引用。

延伸閱讀:.NET Type Fundamentals

+1

謝謝你的回答,它幫助我理解和我會繼續閱讀你添加的鏈接。 – Sev

0

簡短回答:

你做了沒有製作TestObject對象的副本:你只是簡單地生成一個引用這些對象的列表。

爲了製作副本,您應該將Clone()方法添加到您的TestObject類中,並在LINQ查詢的.Select(..)部分中創建一個克隆。

例如:

class TestObject{ 
    string name = "phil"; 

    public void SetName(string name){ 
      this.name = name; 
    } 

    public TestObject Clone() { var result = new TestObject(); result.name = this.name; return result; } 
}

然後用:

example.Values.Where(x => x != null).Select(a => a.Clone()).ToList();

注意,在這種情況下,我們進行了克隆:新TestObject referes到相同string對象。對於string這不是問題,因爲這些是不可變的。製作一個深層克隆也是有用的,其中所有成員也被克隆(直到基元)。

+0

我認爲你應該指定一個深層克隆不MemberwiseClone –