C#委托复制行为疑问:引用类型为何表现类似值类型?
委托作为引用类型的特殊复制行为解析
先看你提供的C# 11示例代码:
file class C { public int IntField1; } file struct S { public int IntField1; } file class StructureVsClassWhenCopying { private static void v1() { System.Console.WriteLine("v1"); } private static void v2() { System.Console.WriteLine("v2"); } public static void Main() { C c1 = new(); c1.IntField1 = 1; C c2 = c1; c1.IntField1 = 2; System.Console.WriteLine(c2.IntField1); // 2, because class is a reference-type S s1 = new(); s1.IntField1 = 1; S s2 = s1; s1.IntField1 = 2; System.Console.WriteLine(s2.IntField1); // 1, because struct is a value type string str1 = "old string"; string str2 = str1; str1 = "new string"; System.Console.WriteLine(str2); // old string, because string is immutable System.Action a1 = v1; System.Action a2 = a1; a1 -= v1; a1 += v2; a2.Invoke(); //v1. Why? } }
你的核心疑问是:委托明明是引用类型,为什么复制后修改原委托,副本不受影响,表现得像值类型或不可变的字符串?
关键原因:委托是不可变的引用类型
和字符串一样,委托实例一旦创建就无法被修改——你看到的+=、-=操作,本质上并不是修改原有委托对象的内部状态,而是创建一个全新的委托实例,然后将这个新实例的引用赋值给原来的变量。
结合代码具体拆解:
System.Action a1 = v1;:创建一个指向v1的委托实例,a1引用这个实例。System.Action a2 = a1;:a2和a1此时指向同一个委托实例(就是那个包含v1的实例)。a1 -= v1;:这个操作不会修改原来的委托实例,而是生成一个新的空委托实例,a1的引用被更新为指向这个新实例。a1 += v2;:再次生成一个新的委托实例(包含v2),a1的引用又指向这个新实例。
而a2自始至终都没有改变过引用指向,它一直指向最初那个包含v1的委托实例,所以调用a2.Invoke()自然会输出v1。
和普通引用类型的区别
普通的引用类型(比如示例中的C),当你修改对象的内部字段时,是直接操作引用指向的对象本身——所以所有指向该对象的变量都会看到变化。但委托的+=/-=是直接替换变量的引用目标,而非修改原对象,这就导致副本的引用不会跟着改变,看起来和值类型的复制行为类似。
内容的提问来源于stack exchange,提问作者user20311258
相关产品推荐
相关产品推荐

