我最近发现我可以使用lambdas来创建简单的事件处理程序。我可以像这样订阅一个点击事件:
button.Click += (s, e) => MessageBox.Show("Woho");
但是如何退订呢?
我最近发现我可以使用lambdas来创建简单的事件处理程序。我可以像这样订阅一个点击事件:
button.Click += (s, e) => MessageBox.Show("Woho");
但是如何退订呢?
c#规范明确指出(IIRC),如果你有两个匿名函数(匿名方法或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);
即使这样,在delegate中实现也很棘手。AutoUnsubscribe,因为您必须创建一个新的EventHandler(它只是一个泛型类型参数)。可行,但很麻烦。