C# 如何删除 lambda 事件处理程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1362204/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 15:39:19  来源:igfitidea点击:

How to remove a lambda event handler

c#eventsevent-handlinglambda

提问by Svish

Possible Duplicates:
Unsubscribe anonymous method in C#
How do I Unregister ‘anonymous’ event handler

可能的重复:
取消订阅 C# 中的匿名方法
如何取消注册“匿名”事件处理程序

I recently discovered that I can use lambdas to create simple event handlers. I could for example subscribe to a click event like this:

我最近发现我可以使用 lambda 来创建简单的事件处理程序。例如,我可以订阅这样的点击事件:

button.Click += (s, e) => MessageBox.Show("Woho");

But how would you unsubscribe it?

但是,您将如何取消订阅?

采纳答案by Jon Skeet

The C# specification explicitly states (IIRC) that if you have two anonymous functions (anonymous methods or lambda expressions) it may or may not create equal delegates from that code. (Two delegates are equal if they have equal targets and refer to the same methods.)

C# 规范明确规定 (IIRC) 如果您有两个匿名函数(匿名方法或 lambda 表达式),它可能会或可能不会从该代码创建相等的委托。(如果两个代表具有相同的目标并引用相同的方法,则它们是相等的。)

To be sure, you'd need to remember the delegate instance you used:

可以肯定的是,您需要记住您使用的委托实例:

EventHandler handler = (s, e) => MessageBox.Show("Woho");

button.Click += handler;
...
button.Click -= handler;

(I can't find the relevant bit of the spec, but I'd be quite surprised to see the C# compiler aggressively try to create equal delegates. It would certainly be unwise to rely on it.)

(我找不到规范的相关部分,但看到 C# 编译器积极尝试创建相等的委托,我会感到非常惊讶。依赖它肯定是不明智的。)

If you don't want to do that, you'll need to extract a method:

如果您不想这样做,则需要提取一个方法:

public void ShowWoho(object sender, EventArgs e)
{
     MessageBox.Show("Woho");
}

...

button.Click += ShowWoho;
...
button.Click -= ShowWoho;

If you want to create an event handler which removes itself using a lambda expression, it's slightly trickier - you need to refer to the delegate within the lambda expression itself, and you can't do that with a simple "declare a local variable and assign to it using a lambda expression" because then the variable isn't definitely assigned. You typically get around this by assigning a null value to the variable first:

如果你想创建一个使用 lambda 表达式删除自身的事件处理程序,它有点棘手 - 你需要在 lambda 表达式本身中引用委托,你不能用简单的“声明一个局部变量并分配使用 lambda 表达式”,因为变量没有明确分配。您通常通过首先为变量分配一个空值来解决这个问题:

EventHandler handler = null;
handler = (sender, args) =>
{
    button.Click -= handler; // Unsubscribe
    // Add your one-time-only code here
}
button.Click += handler;

Unfortunately it's not even easy to encapsulate this into a method, because events aren't cleanly represented. The closest you could come would be something like:

不幸的是,将其封装到方法中甚至并不容易,因为事件没有被清晰地表示。最接近你的可能是这样的:

button.Click += Delegates.AutoUnsubscribe<EventHandler>((sender, args) =>
{
    // One-time code here
}, handler => button.Click -= handler);

Even that would be tricky to implement within Delegates.AutoUnsubscribebecause you'd have to create a new EventHandler(which would be just a generic type argument). Doable, but messy.

即使在内部实现也很棘手,Delegates.AutoUnsubscribe因为您必须创建一个新的EventHandler(这只是一个泛型类型参数)。可行,但混乱。