如何删除lambda事件处理程序

时间:2009-09-01 12:24:52

标签: c# events event-handling lambda

  

可能重复:
  Unsubscribe anonymous method in C#
  How do I Unregister ‘anonymous’ event handler

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

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

但你怎么取消订阅呢?

1 个答案:

答案 0 :(得分:306)

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);

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