我最近发现可以使用lambda表达式创建简单的事件处理程序。例如,我可以像这样订阅点击事件:
button.Click += (s, e) => MessageBox.Show("Woho");
但是你如何取消订阅它?
我最近发现可以使用lambda表达式创建简单的事件处理程序。例如,我可以像这样订阅点击事件:
button.Click += (s, e) => MessageBox.Show("Woho");
但是你如何取消订阅它?
C#规范明确指出(如果我没记错的话),如果你有两个匿名函数(匿名方法或Lambda表达式),它可能会从该代码创建相等的委托,也可能不会。 (如果两个委托具有相等的目标并引用相同的方法,则它们是相等的。)
要确保,您需要记住使用的委托实例:
EventHandler handler = (s, e) => MessageBox.Show("Woho");
button.Click += handler;
...
button.Click -= handler;
(我找不到相关规范的部分,但如果C#编译器试图积极创建相等委托,我会感到非常惊讶。依赖它肯定是不明智的。)
如果您不想那样做,您需要提取一个方法:
public void ShowWoho(object sender, EventArgs e)
{
MessageBox.Show("Woho");
}
...
button.Click += ShowWoho;
...
button.Click -= ShowWoho;
如果你想创建一个使用lambda表达式自我删除的事件处理程序,那么稍微有些棘手-你需要在lambda表达式本身内引用委托,并且你不能通过简单地“声明一个局部变量并使用lambda表达式分配给它”的方式来实现,因为此时该变量并未明确定义。通常情况下,你可以通过首先将变量赋值为空来解决这个问题:EventHandler handler = null;
handler = (sender, args) =>
{
button.Click -= handler; // Unsubscribe
// Add your one-time-only code here
}
button.Click += handler;
很不幸,将此封装为方法甚至都不容易,因为事件没有被清晰地表示出来。你可能能够接近的是类似于以下的东西:
button.Click += Delegates.AutoUnsubscribe<EventHandler>((sender, args) =>
{
// One-time code here
}, handler => button.Click -= handler);
即使在Delegates.AutoUnsubscribe
内部实现这个也会很棘手,因为你需要创建一个新的EventHandler
(它只是一个泛型类型参数)。这是可行的,但会变得混乱。