委托是不可变的,但如何改变

本文关键字:何改变 改变 不可变 | 更新日期: 2023-09-27 18:16:57

向现有委托添加方法时会发生什么?我的意思是,当我将method1添加到del时,del持有method1的地址。当我后来添加method2时,del仍然指向Method1,方法2地址插入在它的底部。这不意味着我更改了委托吗?如果我能改变这一点,为什么书中说"代表是不变的"?

MyDel del = method1; 
del += method2; 
del += method3;

委托是不可变的,但如何改变

您没有更改Delegate对象,而是将del更改为引用不同的对象。

它和字符串完全一样。让我们将您的代码转换为相同的东西,但使用字符串:

string str = "x";
str += "y";
str += "z";

最后,str引用了一个内容为"xyz"的字符串对象。但是您还没有修改内容为"x""y""z"的字符串对象。

代表们也是如此。

del += method2;

相当于:

del = del + method2;

相当于:

del = (MyDel) Delegate.Combine(del, method2);

换句话说,"创建一个新的委托对象,该对象具有引用现有两个委托对象的调用列表"。(如果delmethod2为空,则不需要创建新对象。(

详见Delegate.Combine

让我用一个简单的类比。int是不可变的,所以当你放置时

int x = 123;
x += 1;

它实际上意味着

int _x = x + 1;
x = _x;

当添加一个时,您得到一个新的临时变量_x,然后通过用_x替换来删除初始x;对于代表

del += method2; 

意思完全相同:

delegate _del = delegate.Combine(del, method2);
del = (MyDel) _del;
del += method2;

编译器将其转换为类似于:

del = (MyDel)Delegate.Combine(del, method2);

正如您所看到的,新的委托是从原始委托和附加委托派生的(两者都保持不变(,然后将结果重新分配给原始委托变量。(只有委托对象本身是不可变的,而不是引用它的变量/字段。(

相关问题:+运算符如何组合委托?

和另一个版本,换句话说:

MyDelegate delegateOriginal = Method1;
MyDelegate copyOfOriginal = delegateOriginal;

Object.ReferenceEquals(printAllhandler, anotherHandler); // return true

返回true,因为变量delegateOriginalcopyOfOriginal引用了同一个实例。

然后

delegateOriginal += Method2;

delegate是可变的,那个么下一个表达式将返回true,因为变量将引用相同的对象,但是:

Object.ReferenceEquals(printAllhandler, anotherHandler); // return false

因为delegate是不可变的
delegateOriginal += Method2;行将创建委托的新实例,并将其引用到原始变量。