Problem
I recently found that I can design basic event handlers with lambdas. For instance, I could subscribe to a click event like this:
button.Click += (s, e) => MessageBox.Show("Woho");
However, how would you unsubscribe from it?
Asked by Svish
Solution #1
If you have two anonymous functions (anonymous methods or lambda expressions), the C# standard specifically specifies (IIRC) that it may or may not construct equal delegates from that code. (Two delegates are equivalent if their targets are the same and their methods are the same.)
You’d have to remember which delegate instance you used to be sure:
EventHandler handler = (s, e) => MessageBox.Show("Woho");
button.Click += handler;
...
button.Click -= handler;
(I can’t seem to find the appropriate section of the spec, but I’d be shocked if the C# compiler tried to construct equal delegates aggressively.) It would be foolish to put your faith in it.)
You’ll need to extract a method if you don’t want to do that:
public void ShowWoho(object sender, EventArgs e)
{
MessageBox.Show("Woho");
}
...
button.Click += ShowWoho;
...
button.Click -= ShowWoho;
It’s a little trickier to make an event handler that removes itself using a lambda expression because you have to refer to the delegate within the lambda expression, which you can’t do with a simple “declare a local variable and assign to it using a lambda expression” because the variable isn’t definitely assigned. To get around this, you usually set 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, because events aren’t neatly described, encapsulating this within a method is difficult. Something along these lines would be the closest you could get:
button.Click += Delegates.AutoUnsubscribe<EventHandler>((sender, args) =>
{
// One-time code here
}, handler => button.Click -= handler);
Even that would be difficult to accomplish with Delegates. Because you’d have to create a new EventHandler if you used AutoUnsubscribe (which would be just a generic type argument). It’s doable, but it’s a shambles.
Answered by Jon Skeet
Post is based on https://stackoverflow.com/questions/1362204/how-to-remove-a-lambda-event-handler