[英]Why can't I unsubscribe from an Event Using a Lambda Expression?
本文说明您无法使用Lambda表达式取消订阅事件 。
例如,您可以订阅如下:
d.Barked += (s, e) => Console.WriteLine("Bark: {0}", e);
但是你不能这样取消订阅:
d.Barked -= (s, e) => Console.WriteLine("Bark: {0}", e);
为什么? 这与代表取消订阅有什么区别,例如
EventHandler<string> handler = (s, e) => Console.WriteLine("Bark: {0}", e);
d.Barked += handler;
// ...
d.Barked -= handler;
这一切都归结为:为了代表加法/减法的目的,两位代表何时被认为是相同的。 当取消订阅时,它基本上使用从逻辑Delegate.Remove
,它参考等效两位代表如果两个.Target
和.Method
匹配(至少,对于具有单一的目标方法的委托的简单情况;多播是更很难描述)。 所以:是什么.Method
和.Target
在拉姆达(假设我们将它编译成一个代表 ,而不是一个表达式 )?
编译器实际上在这里有很多自由,但是会发生什么 :
this
标记); target是对此捕获上下文实例的引用(将由捕获范围定义) this
(隐式或显式)使用每个实例状态,则编译器在当前类型上创建实例方法( 方法 ); 目标是当前实例( this
) 然而,它没有做的是将许多lambda与具有相似外观的身体进行比较以减少任何。 所以我编译代码时得到的是两个静态方法:
[CompilerGenerated]
private static void <Main>b__0(object s, string e)
{
Console.WriteLine("Bark: {0}", e);
}
[CompilerGenerated]
private static void <Main>b__2(object s, string e)
{
Console.WriteLine("Bark: {0}", e);
}
(这里的Main
是因为在我的测试装备中,那些lambdas在Main
方法中 - 但最终编译器可以选择它在这里选择的任何不可发音的名称)
第一种方法由第一种lambda使用; 第二种方法由第二种lambda使用。 最终,它不起作用的原因是因为.Method
不匹配。
在常规的C#术语中,它会像:
obj.SomeEvent += MethodOne;
obj.SomeEvent -= MethodTwo;
其中MethodOne
和MethodTwo
包含相同的代码; 它没有取消订阅任何东西。
如果编译器发现这一点可能会很好 ,但它不是必需的 ,因此它更安全,它不会选择 - 它可能意味着不同的编译器开始产生非常不同的结果。
作为旁注; 如果它确实试图去重复它可能会非常混乱,因为你也有捕获上下文的问题 - 那么它会在某些情况下“工作”而不是其他情况 - 而不是显而易见的 - 可能最糟糕的情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.