本文说明You Can’t Unsubscribe from an Event Using a Lambda Expression。
E.g。您可以按以下方式订阅:
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;
答案 0 :(得分:37)
这一切都归结为:为了代表加法/减法的目的,两位代表何时被认为是相同的。当您取消订阅时,它基本上使用Delegate.Remove
中的逻辑,如果.Target
和.Method
都匹配,则认为两个代理是等效的(至少对于委托的简单情况)单个目标方法;多播更难以描述)。那么:lambda上的.Method
和.Target
是什么(假设我们将它编译为委托,而不是表达式)?
编译器实际上有很多自由,但发生的是:
this
(隐式或显式)使用每个实例状态,则编译器会创建一个实例方法(方法)对当前类型; 目标是当前实例(this
)this
(这里的[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);
}
只是因为在我的测试装备中,这些lambda属于Main
方法 - 但最终编译器可以选择它在这里选择的任何不可发音的名称。
第一个方法由第一个lambda使用;第二种方法由第二种lambda使用。最终,它不起作用的原因是因为Main
不匹配。
在常规的C#术语中,它就像在做:
.Method
其中obj.SomeEvent += MethodOne;
obj.SomeEvent -= MethodTwo;
和MethodOne
内部具有相同的代码;它没有取消订阅。
如果编译器发现了这个很好,但不需要,因此它不会选择<更安全< / em> to - 这可能意味着不同的编译器开始产生非常不同的结果。
作为旁注;如果它做尝试去重复,那可能会非常混乱,因为你也有捕获上下文的问题 - 那么它会在某些情况下“工作”而不是其他情况 - 没有明显的 - 可能是最糟糕的情况。