【问题标题】:Copy Reference Type from one to another C#将引用类型从一个复制到另一个 C#
【发布时间】:2016-06-10 13:14:15
【问题描述】:

下面是我的课

 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 的值发生更改。

【问题讨论】:

  • obj.name 的值在您更改 newobj.name 时会发生变化,因为它们是相同的newobjobj 都指向内存中的相同位置。它们只是对同一对象的不同引用。如果你想创建一个真正的副本,你必须创建一个方法来构造一个new Test() 并相应地设置新对象的属性。
  • 换句话说 - newobj 是对 obj 引用的同一对象的另一个引用
  • Test 是一个引用类型。
  • 确保这些对象不链接的方法是创建一个新的'newobj'

标签: c#


【解决方案1】:

您不是在创建副本,您只是将一个对象的引用 (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);
 }
}

【讨论】:

【解决方案2】:

正如 cmets 中提到的,obj 和 newObj 都指向同一个底层内存对象,这就是为什么改变一个对象也会改变另一个对象。这是因为它们是 reference 类型(与 value 类型相反)。如果你想要两个不同的对象,你有几个选择。首先是创建一个新对象并手动分配属性:

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

第二个选项是克隆对象。虽然有很多方法可以做到这一点(反射、序列化、表达式树、第三方库),但我发现使用序列化是执行克隆的最简单方法,前提是您不打算每秒执行数千次.有关使用 BinaryFormatter 克隆对象的信息,请参阅下面的答案。

Cloning List<T>

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:
      var newobj = obj; 
      

      这导致 obj 的引用被分配给 newobj。它们与上述语句指向的内存位置确实没有区别。 如果您想拥有一个具有相同值但在 newobj 的值更改时不受影响的 obj,您应该这样做。

         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";
      

      【讨论】:

        【解决方案5】:

        你买了一套新公寓。你会得到一组钥匙,让你可以进入那间公寓。你雇人打扫你的公寓,然后给他一份副本你的设置钥匙,这样他就可以进去了。当您深夜下班回家时,您的公寓很干净!怎么会?

        这个愚蠢的比喻正是你的代码中发生的事情:

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

        这里要清楚了解的重要一点是objnewObj 不是 Test 的实例。变量中存储的值是对象所在的内存地址

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

        值类型完全不同,但那是另一回事了。

        【讨论】:

          猜你喜欢
          • 2017-06-23
          • 2010-11-15
          • 2012-03-06
          • 1970-01-01
          • 2011-08-11
          • 2021-03-25
          • 1970-01-01
          • 2018-10-19
          • 1970-01-01
          相关资源
          最近更新 更多