2016-06-10 50 views
1

複製引用類型下面是我的課從一個到另一個C#

public Class Test 
{ 
    int id {get;set;} 
    string name {get;set;} 
} 

我創建這個類的一個對象,並分配值。

var obj = new Test(); 
    obj.id = 1; 
    obj.name = "test"; 
    var newobj = obj; 
    newobj.name ="NewTest"; 

下面是輸出

Console.WriteLine(obj.name); //NewTest 
    Console.WriteLine(newobj.name); //NewTest 

爲什麼當我改變存在於新的obj一個屬性的值obj的值正在改變。我知道它的解決方案,我不知道爲什麼我無法找到。如果我在newobj中更改了值,我不希望obj的值得到改變。

+3

當您更改'newobj.name'時,'obj.name'的值正在改變,因爲它們是*相同的事物*。 'newobj'和'obj'都指向內存中的相同位置。它們只是對同一個*對象*的不同*引用*。如果你想創建一個真正的副本,你將不得不創建一個方法來構造一個新的Test(),並相應地設置這個新對象的屬性。 –

+0

用換句話說 - newobj是obj引用的另一個引用 – JeffRSon

+0

'Test'是一個引用類型。 –

回答

5

沒有創建一個副本創建相同的實例,你只是分配一個對象的引用(obj)到另一個變量(newobj)。訪問它們中的任何一個都指向內存中的相同位置。

要創建一個對象的副本,您必須克隆它。例如參見https://stackoverflow.com/a/78612/1028323 https://stackoverflow.com/a/129395/1028323

public static T DeepClone<T>(T obj) 
{ 
using (var ms = new MemoryStream()) 
{ 
    var formatter = new BinaryFormatter(); 
    formatter.Serialize(ms, obj); 
    ms.Position = 0; 

    return (T) formatter.Deserialize(ms); 
} 
} 
+0

深克隆:http://stackoverflow.com/questions/129389/how-do-you-do-a-deep-copy-an- object-in-net-c-specific –

+0

參考我提供的答案,無論如何。 – Alex

+1

是的,只需添加更多的上下文。讓我給你一個upvote。 –

2

newobj沒有創建一個新的實例......它只是一個指針,你var obj = new Test();

3

正如在評論中提到,無論是OBJ和newObj都指向同一個底層的內存對象,這就是爲什麼在一個不斷變化的東西也改變對其他的東西。這是因爲他們是參考類型(而不是類型)。如果你想要兩個不同的物體,你有兩個選擇。首先是創建一個新對象並手動分配屬性:

var test1 = new Test() { id = 1, name = "Foo } 
var test2 = new Test() { id = test1.id, name = test1.name } 

第二個選項是克隆該對象。雖然有很多方法可以做到這一點(反射,序列化,表達式樹,第三方庫),但我發現使用序列化是執行克隆的最簡單方法,前提是您不打算每秒執行數千次。有關使用BinaryFormatter克隆對象的信息,請參閱下面的答案。

Cloning List<T>

0
var newobj = obj; 

這導致obj的參考會被分配給newobj。在上面的語句中,它們指向的內存位置實際上沒有差別。 如果你想有一個obj具有相同的值,但保持不受影響,當newobj的值改變時,你應該這樣做。

var obj = new Test(); 
    obj.id = 1; 
    obj.name = "test"; 
    var newobj = new Test(); 
    newobj.id = obj.id; 
    newobj.name = obj.name; 
    newobj.name ="NewTest"; 
0

你買了一套新的公寓。你得到一組鑰匙,讓你進入該公寓。你僱人來清理你的公寓,你給他一個副本你的設置鑰匙,讓他可以進去。當你深夜下班回家時,你的公寓很乾淨!怎麼來的?

這愚蠢的比喻正是什麼在你的代碼發生的事情:

  • Testnew創建的實例是你的公寓。
  • obj是你的一套鑰匙。
  • newObj是您提供清潔服務的副本。
  • 更改Name正在清理你的公寓(以某種方式修改對象)。

瞭解清楚這裏最重要的是,objnewObjTest實例。存儲在變量中的值是對象所在的存儲器地址

通過同一把鑰匙,您可以訪問您的公寓,變量objnewObj可讓您訪問他們指向的對象。當您將變量obj複製到newObj時,您只是簡單地複製訪問對象的方式(內存地址),而不是對象本身。

事情與價值類型有着根本的不同,但那是另一回事。