委托是不可变的,但如何改变
本文关键字:何改变 改变 不可变 | 更新日期: 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);
换句话说,"创建一个新的委托对象,该对象具有引用现有两个委托对象的调用列表"。(如果del
或method2
为空,则不需要创建新对象。(
详见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,因为变量delegateOriginal
和copyOfOriginal
引用了同一个实例。
然后
delegateOriginal += Method2;
若delegate
是可变的,那个么下一个表达式将返回true,因为变量将引用相同的对象,但是:
Object.ReferenceEquals(printAllhandler, anotherHandler); // return false
因为delegate
是不可变的
第delegateOriginal += Method2;
行将创建委托的新实例,并将其引用到原始变量。