Events and Lambda Expressions

Something I was pondering about today.  Say, I have a class and I would like to subscribe to an event it raises, handle it once, and unsubscribe.  Pretty easy scenario, and the code is just as simple.

Here is my simple class with event arguments:

using System;

 

namespace EventsDemo

{

  public class EventProvider

  {

    public string RandomData { get; set; }

 

 

    public void RaiseEvent()

    {

      OnRandomEvent(RandomData);

    }

 

    public event EventHandler<RandomEventArgs> RandomEvent;

 

    protected void OnRandomEvent(string data)

    {

      if (RandomEvent != null)

      {

        RandomEvent(this, new RandomEventArgs(data));

      }

    }

  }

}

 

using System;

 

namespace EventsDemo

{

  public class RandomEventArgs : EventArgs

  {

    private RandomEventArgs() { }

 

    public RandomEventArgs(string data)

    {

      Data = data;

    }

    public string Data { get; private set; }

  }

}

 

Of course, my console sample application is just as easy:

using System;

 

namespace EventsDemo

{

  class Program

  {

    static void Main(string[] args)

    {

      string extraData = "extra data";

 

      EventProvider provider = new EventProvider() { RandomData = "something" };

      provider.RandomEvent += new EventHandler<RandomEventArgs>(provider_RandomEvent);

      provider.RaiseEvent();

      Console.ReadKey();

    }

 

    static void provider_RandomEvent(object sender, RandomEventArgs e)

    {

      Console.WriteLine(e.Data);

      EventProvider provider = sender as EventProvider;

      provider.RandomEvent -= new EventHandler<RandomEventArgs>(provider_RandomEvent);

    }

 

 

  }

}

 

However, I am accustomed to just handle events as lambda expressions as I find that syntax much cleaner and easier to follow:

 

using System;

 

namespace EventsDemo

{

  class Program

  {

    static void Main(string[] args)

    {

      string extraData = "extra data";

 

      EventProvider provider = new EventProvider() { RandomData = "something" };

      provider.RandomEvent += (o, e) => { Console.WriteLine(e.Data); };

 

      provider.RaiseEvent();

      Console.ReadKey();

    }

 

 

  }

}

 

Now is the question.  How do I unsubscribe from the event in my lambda expression?  I cannot do what I did before, since I do not have a handler to use for –= call.  So, I have to declare my handler separately.  Here is modified code:

using System;

 

namespace EventsDemo

{

  class Program

  {

    static void Main(string[] args)

    {

      string extraData = "extra data";

      EventProvider provider = new EventProvider() { RandomData = "something" };

 

      EventHandler<RandomEventArgs> handler = null;

      handler = (o, e) => { Console.WriteLine(e.Data); provider.RandomEvent -= handler; };

      provider.RandomEvent += handler;

 

      provider.RaiseEvent();

 

      provider.RaiseEvent();

 

      Console.ReadKey();

    }

 

 

  }

}

 

I am calling RaiseEvent twice to ensure I did indeed unsubscribe.  Now what is the advantage to this approach you say?  Closures is my number one reason along with clean code as close second.  Here is the final version:

using System;

 

namespace EventsDemo

{

  class Program

  {

    static void Main(string[] args)

    {

      string extraData = "extra data";

      EventProvider provider = new EventProvider() { RandomData = "something" };

 

      EventHandler<RandomEventArgs> handler = null;

      handler = (o, e) => { Console.WriteLine(e.Data + "-" + extraData); provider.RandomEvent -= handler; };

      provider.RandomEvent += handler;

 

      provider.RaiseEvent();

 

      provider.RaiseEvent();

 

      Console.ReadKey();

    }

 

 

  }

}

 

As you can see, I use closure and take advantage of the scope in which my extraData variable is declared, thus combining data in the event with that variable.  I could not do this in my first example without making extraData variable public.  In this quick post I demonstrated how to unsubscribe from events where handlers are implemented as lambda expression as well as outlined the reasons why one might want to use this approach.  Why would you want to unsubscribe?  Typically, your handlers would be cleaned up, but what if your code throws an exception inside lambda expression?  In this case next time you raise the event, it will be handled twice.  Also, I am a big fan of cleaning up event handlers as they are a major source of potential memory leaks.

Thanks.

Leave a Reply

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