混淆结构体内部的列表(值类型vs引用类型)

本文关键字:类型 vs 引用类型 列表 结构体 内部 | 更新日期: 2023-09-27 18:03:14

所以我今天发现结构体和类在c#中用于分配变量时的行为不同。根据我的理解,当我将一个结构体赋值给一个变量时,该变量存储该结构体的副本,当我将一个类赋值给一个变量时,该变量存储对该类实例的引用。

在这种情况下,dad2包含dad1的副本,所以我对dad2所做的任何事情不应该影响到dad1吗?显然情况并非如此,因为当我向dad2添加子元素时,它也会向dad1添加相同的子元素。

public struct Dad {
        public string name;
        public List <Son> sons;
        public struct Son {
            public string name;
            public Son (string n) {
                name = n;
            }
        }
    }
    static void Main (string [] args) {
        Dad dad1 = new Dad ();
        dad1.name = "Bob";
        dad1.sons = new List <Dad.Son> {new Dad.Son ("A")};
        Dad dad2 = dad1;
        Debug.WriteLine (dad2.Equals (dad1) + " " + dad1.sons.Count () + " " + dad2.sons.Count ());
        //true 1 1
        dad2.sons.Add ( new Dad.Son ("B"));
        Debug.WriteLine (dad2.Equals (dad1) + " " + dad1.sons.Count () + " " + dad2.sons.Count ());
        //true 2 2
    }

混淆结构体内部的列表(值类型vs引用类型)

是的,它复制了结构体内部的值-在结构体内部有一个对List的引用,因此引用也被复制-这是一个"浅复制"…如果List被复制到一个新的对象,这将是一个"深度复制"…结构赋值使用"复制"语义,这取决于每个成员的复制语义…见http://msdn.microsoft.com/en-us/library/saxz13w4.aspx

将类类型变量和字段视为持有"实例ID ",一切都将清楚。假设List类型的结构字段Foo的值为"实例ID#95341"。复制该结构体将产生另一个结构体,其字段"Foo"也包含"实例ID#95341"。调用Foo。添加一个这样的结构体将向"实例ID #95341"引用的列表中添加一个元素。查询Foo。在另一个这样的结构体上Count将从"实例ID #95341"引用的列表中获取计数,这将自然是相同的列表。

我在回答这个问题

所以我对爸爸2做的任何事都不应该影响到爸爸1吗?"

在您的代码中, 中的任何更改
public List <Son> sons;

出现在两个副本中(dad1和dad2);但是

的任何变化
public string name;

只在

改变的对象上出现

示例-只修改dad2的名称,不修改dad1的名称

Dad dad1 = new Dad();
dad1.name = "Bob";
dad1.sons = new List<Dad.Son> { new Dad.Son("A") };
Dad dad2 = dad1;
Console.WriteLine(dad2.Equals(dad1) + " " + dad1.sons.Count() + " " + dad2.sons.Count());
//true 1 1
dad2.sons.Add(new Dad.Son("B"));
Console.WriteLine(dad2.Equals(dad1) + " " + dad1.sons.Count() + " " + dad2.sons.Count());
//true 2 2
dad2.name = "Tom";
Console.WriteLine(dad2.Equals(dad1) + " " + dad1.sons.Count() + " " + dad2.sons.Count());
//False 2 2