如何删除 lambda 事件处理程序

发布于 2024-08-04 08:18:49 字数 151 浏览 8 评论 0原文

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

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

但是如何取消订阅呢?

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

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

But how would you unsubscribe it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不如归去 2024-08-11 08:18:49

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 表达式”,因为这样变量就没有被明确赋值。通常,您可以通过首先为变量分配 null 值来解决此问题:

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

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

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

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:

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.AutoUnsubscribe because you'd have to create a new EventHandler (which would be just a generic type argument). Doable, but messy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文