Anonymous methods as event handlers – Part 1

The syntactic sugar offered by anonymous methods makes them great candidates for writing event handlers; together with smart type inference, they reduce the amount of code written by an order of magnitude.

And that’s without considering the power offered by closures. With event handlers, closures allow you to kind of “stuff” extra parameters into the handler, without changing the actual number of formal parameters. This blog post shows a situation where an anonymous method acting as an event handler makes code simpler, and then goes on to show a gotcha with un-subscription and anonymous methods.

Here’s a simple Control class that fires a bunch of events.

   1: class Control


   2: {


   3:     public class ControlEventArgs : EventArgs


   4:     {


   5:         public Control Control {get;set;}


   6:     }


   7:  


   8:     public bool Enabled { get; set; }


   9:  


  10:     public event EventHandler<ControlEventArgs> KeyPressed;


  11:     public event EventHandler<ControlEventArgs> LeftButtonClicked;


  12:     public event EventHandler<ControlEventArgs> RightButtonClicked;


  13:     public event EventHandler<ControlEventArgs> MouseMoved;


  14: }

Let’s say you’re developing a GUI application with this class, and you want to handle events only if the originating control is visually enabled i.e., Enabled set to true. Pretty reasonable constraint, but tedious to implement, if you go the standard way of adding the check to the start of each of your event handlers.

   1: class GUIApp


   2: {


   3:     public void Initialize()


   4:     {


   5:         Control control = new Control();


   6:         control.KeyPressed += new EventHandler<Control.ControlEventArgs>(control_KeyPressed);


   7:         control.MouseMoved += new EventHandler<Control.ControlEventArgs>(control_MouseMoved);


   8:     }


   9:  


  10:     void control_MouseMoved(object sender, Control.ControlEventArgs e)


  11:     {


  12:         if (e.Control.Enabled)


  13:         {


  14:             /// 


  15:         }


  16:     }


  17:  


  18:     void control_KeyPressed(object sender, Control.ControlEventArgsEventArgs e)


  19:     {


  20:         if (e.Control.Enabled)


  21:         {


  22:             ///


  23:         }


  24:     }


  25: }

With an anonymous method, you could write a far more terse and easy to maintain version

   1: class GUIApp


   2: {


   3:     public void Initialize()


   4:     {


   5:         Control control = new Control();


   6:         control.KeyPressed += IfEnabledThenDo(control_KeyPressed);


   7:         control.MouseMoved += IfEnabledThenDo(control_MouseMoved);


   8:     }


   9:  


  10:     public EventHandler<Control.ControlEventArgs> IfEnabledThenDo(EventHandler<Control.ControlEventArgs> actualAction)


  11:     {


  12:         return (sender, args) => { if (args.Control.Enabled) { actualAction(sender, args); } };


  13:     }


  14:  


  15:     void control_MouseMoved(object sender, Control.ControlEventArgs e)


  16:     {


  17:         ///


  18:     }


  19:  


  20:     void control_KeyPressed(object sender, Control.ControlEventArgs e)


  21:     {


  22:         ///


  23:     }


  24: }

IfEnabledThenDo returns an anonymous function that first checks whether the control is enabled before calling the actual function. The code is much shorter, and the condition is checked only in one place, which makes it easy to modify or add additional logic without having to remember to change every single event handler. Plus, the reads like an English statement – subscribe to the event and if enabled, then do whatever else is necessary.

Great, but unless you are a masochist who revels in littering the code base with hard to reproduce bugs that bomb your app only when demoing to your most important customer, you must, of course, write code to unsubscribe. But there’s no method name to refer to, so you do it the same way as you did when subscribing.

   1: public void Initialize()


   2: {


   3:     control.KeyPressed += IfEnabledThenDo(control_KeyPressed);


   4:     control.MouseMoved += IfEnabledThenDo(control_MouseMoved);


   5: }


   6:  


   7: public void Destroy()


   8: {


   9:     control.KeyPressed -= IfEnabledThenDo(control_KeyPressed);


  10:     control.MouseMoved -= IfEnabledThenDo(control_MouseMoved);


  11: }



This, unfortunately, won’t work – the application will still remain subscribed to those events. Can you figure out why?



Answer and more in the next blog post.

One thought on “Anonymous methods as event handlers – Part 1”

  1. A delegate is identified by its target (method, instance\type). In the above case, the delegates returned by IfEnabledThenDo during registrationg\unregistration target methods that belong to two different instances of the compiler generated class (that holds the anonymous delegate method). Hence the delegate instance returned in the line of unregistration does not exist with the event invocation list; in other words the subscribed event handler is not removed.

    http://vivekragunathan.spaces.live.com/blog/cns!753E720D857C98F6!533.entry

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>