Named Handlers when registering to events with Lambda Expressions

Topics: C# Language Design
May 19, 2014 at 9:15 PM
Declaring event handlers with lambda expressions is a time saver, especially when dealing with a few sentences, like:
myButton1.Click += (s, a) => MessageBox.Show("Clicked!");
The problem with this approach is that there is no way later on in the code to unregister the event handler from the event. Thus, in order to solve this situation one may write either ...:
EventHandler myHandler = (s, a) => MessageBox.Show("Clicked!");
...
myButton1.Click += myHandler;
...
myButton1.Click -= myHandler;
...
... or ...
...
myButton1.Click += DisplayMessage;
...
myButton1.Click -= DisplayMessage;
...
public void DisplayMessage (object sender, EventArgs e)
{
     MessageBox.Show("Clicked!");
}
Thus, the proposal is implementing the possibility to declare a name for anonymous event handlers created with lambda expressions:
myButton1.Click += hdrDisplayMessage: (s, a) => MessageBox.Show("Clicked!");
...
myButton1.Click -= hdrDisplayMessage;
What would be translated by the compiler to something like:
EventHandler hdrDisplayMessage = (s, a) => MessageBox.Show("Clicked!");
...
myButton1.Click += hdrDisplayMessage;
...
myButton1.Click -= hdrDisplayMessage;
...
Thoughts?
May 19, 2014 at 11:53 PM
With the currently proposed C# 6, you can already do something very similar:
button.Click += (EventHandler displayMessage = (s, a) => MessageBox.Show("Clicked!"));

button.Click -= displayMessage;
May 20, 2014 at 3:00 AM
What's the scope of such reference? Member field? Local field? ( I guess you can also use var there)
May 20, 2014 at 7:36 AM
Sorry there is a better method pioneered by F#. All events should be exposed as IObservable<EventArgs> then you can do
IDisposable subscription = button.Click.Subscribe(e=>Console.WriteLine("Clicked");
then when you want to unsubscribe you just do
subscription.Dispose();
The added benefit of using IDisposable is that you can use LINQ;
IDisposable s = button.Click
    .Throttle( TimeSpan.FromSeconds(0.1) )
    .Subscribe( e => Console.WriteLine("Clicked"));      
May 20, 2014 at 11:11 AM
Ultrahead wrote:
What's the scope of such reference? Member field? Local field? ( I guess you can also use var there)
It's a local variable. And you can't use var there, you can't use var with lambdas, because it's not clear what delegate type do you want.
May 20, 2014 at 2:25 PM
Edited May 20, 2014 at 2:25 PM
svick wrote:
It's a local variable. And you can't use var there, you can't use var with lambdas, because it's not clear what delegate type do you want.
Ah, I see.

It's good to know it but it's not what I'm looking for since the variable is local. The idea is that the compiler automatically creates a private member field for the event handler when it finds a sentence like:

myButton1.Click += hdrDisplayMessage: (s, a) => MessageBox.Show("Clicked!");.
May 20, 2014 at 2:36 PM
Edited May 20, 2014 at 2:37 PM
@bradphelan: it looks good, indeed. The question is what happens when you have an event that does not follow MSFT guidelines of having the sender and an EventArgs object? And instead, for example, you return a struct as argument (along with the sender or not)?
May 21, 2014 at 5:46 AM
Have a look at

http://msdn.microsoft.com/en-us/library/ee340439.aspx

which is how F# exposes .Net events. They are both IObservable<TARgs> and IDelegateEvent<TDelegate>. I think this means they can support pretty much any type of event structure.
May 21, 2014 at 3:46 PM
That is interesting. Thanks for the link.