C# 委托充当值类型

C# 委托充当值类型,c#,delegates,C#,Delegates,我刚刚发现了一件奇怪的事情: Action a1 = () => Console.Write("1 "); Action a2 = () => Console.Write("2 "); Action tmp = a1; a1 += a2; a2 = tmp; Console.Write("a1:\t"); a1(); //a1: 1 2 Console.Write("\na2:\t"); a2(); //a2: 1 Console.ReadLine(); 我希望这两个语

我刚刚发现了一件奇怪的事情:

Action a1 = () => Console.Write("1 ");
Action a2 = () => Console.Write("2 ");
Action tmp = a1;
a1 += a2;
a2 = tmp;
Console.Write("a1:\t");
a1();   //a1:  1 2
Console.Write("\na2:\t");
a2();   //a2:  1
Console.ReadLine();
我希望这两个语句都返回“12”;
为什么不是这样?

原因是,在添加附加事件之前,您将temp变量分配给了a1,这修改了事件要执行的操作。如果您希望得到与“12”相同的结果,您应该执行以下操作:

a1 += a2;
a2 = a1;
这将导致与您期望的结果相同的结果。另一种方法是,如果您这样做:

a1 += a2;
Action temp = a1;
a2 = temp;

这也会产生您期望的结果。

是的,委托是引用类型。它们也是不可变的,如System.String。这让很多人感到惊讶。想象一下,您有相同的字符串代码。我认为这更清楚:

String s1 = "1 ";
String s2 = "2 ";
String stmp = s1;
s1 += s2;
s2 = stmp;
Console.WriteLine(s1);  //  1 2
Console.WriteLine(s2);  //  1
调用
+=
不会改变委托的基础实例,它会生成一个新委托,并将右侧附加到新委托的调用列表中<代码>+=实际上只是
委托的糖分。组合
,编译器将生成类似于以下内容的代码:

a1 = (Action)Delegate.Combine(a1, a2);

我认为这使我们更清楚地看到,我们正在创建一个委托的新实例。

委托是引用类型。它们也是不可变的,就像字符串一样。@mike谢谢你的快速回答!我觉得这很违反直觉。。因此,如果我想引用一个委托(一个从不同对象调用的动作的可变集合),我应该将它包装到一个类中?是的,如果你想让其他类看到这些变化,你必须将它包装到一些东西中。同样,类似于字符串。如果希望多个协作类获得相同的值,则它们需要对同一(可变)对象的引用。@mike,谢谢。你知道让代理不可变的原因吗?对不起,我不知道为什么它们是不可变的。