【问题标题】:How to remove a lambda event handler [duplicate]如何删除 lambda 事件处理程序 [重复]
【发布时间】:2010-11-24 15:14:08
【问题描述】:

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

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

但是你会如何退订呢?

【问题讨论】:

标签: c# events event-handling lambda


【解决方案1】:

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(这将只是一个泛型类型参数)。可行,但很混乱。

【讨论】:

  • 没错,如果您使用 Reflector 查看编译后的程序集,您会注意到编译器在您使用 lambda 时已经为您创建了一个指针,只是您在 Visual 中看不到它工作室
  • @Raffaeu:称它为指针有点误导 - 它不是正常 C# 意义上的指针。
  • 是的,抱歉,“编译器无论如何都会创建处理程序变量”更好吗? :)
  • @Raffaeu:可能:)
  • @DynamicLynk:我很想看到代码 - 我强烈怀疑它实际上并没有像你想象的那样表现。你可以问一个新问题(“当 Jon Skeet 声称它不应该这样做时,为什么它会起作用......”)或者只是私下给我发邮件。
猜你喜欢
  • 1970-01-01
  • 2016-07-05
  • 1970-01-01
  • 2011-09-21
  • 1970-01-01
  • 1970-01-01
  • 2020-01-12
  • 2012-05-10
  • 1970-01-01
相关资源
最近更新 更多