Event delegates and exception handling

Delegates

This blog post will focus on handling exceptions thrown by event delegates.

But first we will briefly discuss what a delegate is. If you know C or C++ it is natural to think of delegates as function pointers. Why is this handy? Let’s say that I have an API that will read a list of car objects from a database and return that list to the user. Something like this:

    public IEnumerable GetCars()
    {
      var cars = new List<Car>();
      //Get all cars from database
      return cars;
    }

    public class Car
    {
      //define car properties like color, weight, brand etc.
    }

Nothing fancy here. Now lets say we want to let the users of our API to be able to filter the cars – for instance only return red cars. We could make a new API method to return a specific color of cars, but we really can’t guess what the user would like to filter on – it would be much nicer if the user could provide us with at filter method to use.  First we define what the filter shall look like, and then we use it in out API:

   public delegate bool Filter(Car car);

    public IEnumerable GetCars(Filter filter)
    {
      var cars = new List<Car>();
      //Get all cars from database and the apply filter
      return cars.Where(car => filter(car));
    }

Now we can define and use a filter that returns red cars:

    public bool CarIsRed(Car car)
    {
      return car.Color == ConsoleColor.Red;
    }

    public void useGetCars()
    {
      var filteredCars = GetCars(CarIsRed);
      //do sutff with cars
    }

But the user could supply any kind of filter he desired.

So that was delegates – what is an events?
And how is it different from a delegate?

A C# event is collection of delegates that can be called by the event. So the event itself is not a delegate but you can add delegates to it using the += operator and remove them again using the –= operator.

In the following example a timer is startet, and every second the timer calls the DoTick method. The DoTick method fires the Tick event if there are any subscribers. In our case there are two subscribers Tick and Tick2 – that will write to the console.

  public class Program
  {
    private static void Main(string[] args)
    {
      var t = new Ticker();
      t.Tick += t_Tick;
      t.Tick += t_Tick2;

      Console.ReadKey();
    }

    private static void t_Tick2(object sender, EventArgs e)
    {
      Console.WriteLine("Tick2");
    }

    private static void t_Tick(object sender, EventArgs e)
    {
      //throw new Exception("boom!!");
      Console.WriteLine("Tick1");
    }
  }

  public class Ticker
  {
    private Timer timer;
    public event EventHandler<EventArgs> Tick;

    public Ticker()
    {
      timer = new System.Threading.Timer(DoTick, null, 1000, 1000);
    }

    private void DoTick(object state)
    {
      if (Tick != null)
        Tick(this, new EventArgs());
    }
  }

This works fine – but in the t_Tick method I have hinted at a problem. What if one of the event handlers (subscribers) throws an exception? That is the topic of the next section.

What happens if one of the event handlers throws an exception.

As the code in DoTick is written now the application will be terminated – not so nice. If you are in complete control of your application you should have normal exception handling in each event handler, so execptions aren’t propagated back to the place where the event was fired from.

What if I’m not in complete control of the application?

Maybe your application has support for third party plugins and the event handlers could belong to two different plugins provided by different manufactures. One of the plugins throws an exception, and we are not interested in our application going boom! The first thing you try is to rewrite DoTick like this:

    private void DoTick(object state)
    {
      try
      {
      if (Tick != null)
        Tick(this, new EventArgs());
      }
      catch (Exception)
      {
        //do exception handling, log the error etc.
      }
    }

Now our application doesn’t crash anymore, but what happens is that the  event handlers are called one at a time, and then an event handler throws an exception, it is caught, but the rest of the event handlers will not be called, meaning that one defect event handler will ruin it for everybody else.

Instead we can use the fact that an event contains a collection of delegates and that each delegate can be invoked by calling DynamicInvoke on it:

    private void DoTick(object state)
    {
      if (Tick != null)
      {
        foreach (var @delegate in Tick.GetInvocationList())
        {
          try
          {
            @delegate.DynamicInvoke(this, new EventArgs());
          }
          catch (Exception)
          {
            //do exception handling, log the error etc.
          }
        }
      }
    }

Now only the defect event handler will fail and every body else will be able to do their job.

I don’t want to write that ugly code every time I fire an event.

Yes the code is somewhat ugly and it is quite a lot to write just so we can fire an event. I already think that having to check for null is kind of stupid, since that is what you do every time – and this is event worse. Therefore I suggest to create an extensiuo method, that works for events that use the EventHandler signature. (which is what is generally recommende, so of corse you use that for all your event handlers).

  public static class Utils
  {
    public static void FireEvent<T>(this EventHandler evt, object sender, T eventArgs)
    {
      if (evt != null)
      {
        foreach (var @delegate in evt.GetInvocationList())
        {
          try
          {
            @delegate.DynamicInvoke(sender, new EventArgs());
          }
          catch (Exception)
          {
            //do the exception handling
          }
        }
      }      
    }
  }

Now that we have written this code once and for all, and we can fire events like this:

private void DoTick(object state)
{
  Tick.FireEvent(this, new EventArgs());
}

Wow, that’s really nice

Yes it is – you should of corse still make sure that the error handling in the try-catch in the extension method do something appropriate like logging the error, disble the offending plug-in or whatever makes sense in your situation.

Advertisements

About Lund

Owner of iCodeIT, a software consulting company. I am primarily working the .NET development and architecture.
This entry was posted in C#. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s