将参考类型从一个复制到另一个C#

时间:2016-06-10 13:14:16

标签: 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的值被改变。

5 个答案:

答案 0 :(得分: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);
 }
}

答案 1 :(得分: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>

答案 2 :(得分:2)

newobj未创建新实例...它只是指向您使用var obj = new Test();创建的同一实例的另一个指针

答案 3 :(得分: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";

答案 4 :(得分:0)

你买了一套新公寓。您将获得一组钥匙,可以访问该公寓。你雇人来清理你的公寓,然后你给他一套复制你的固定钥匙,这样他就可以进去了。当你深夜下班回家时,你的公寓很干净!怎么样?

这个愚蠢的比喻正好在你的代码中发生了什么:

  • 您使用Test创建的new实例是您的公寓。
  • obj是您的一组密钥。
  • newObj是您提供清洁服务的副本。
  • 更改Name正在清理您的公寓(以某种方式修改对象)。

要清楚明白这一点,重要的是objnewObj 不是 Test的实例。存储在变量中的值是对象存在的内存地址

与密钥相同,您可以访问公寓,变量objnewObj可让您访问他们所指向的对象。将变量obj复制到newObj时,您只需复制访问对象(内存地址)的方法,而不是对象本身。

事物与价值类型截然不同,但这是另一个故事。