Tips & Tricks: Exceptions and Events

Exceptions are the preferred way to threat “exceptional” cases in C#. An Exception is an object that contains information about an error that happened at some point in the execution of a program. 

Events in C# are convenient wrappers around delegates that help implement the publish-subscribe pattern.

In the example below, a CPU class has been defined. The CPU class defines an UsageChanged event that clients can use to subscribe and get notifications related to the CPU usage:

using System;

class Program
{
    static void Main()
    {
        var cpu = new CPU();

        cpu.UsageChanged += (sender, percentage) => 
            Console.WriteLine("Handler1: Cpu Usage: {0} %", percentage);

        cpu.UsageChanged += (sender, percentage) =>
        {
            Console.WriteLine("Handler2: Cpu Usage: {0} %", percentage);
            throw null; 
        };

        cpu.UsageChanged += (sender, percentage) =>
            Console.WriteLine("Handler3: Cpu Usage: {0} %", percentage);

        cpu.DoWork();
    }
}

class CPU
{
    public event EventHandler<int> UsageChanged = delegate { };

    public void DoWork()
    {
        var random = new Random();
        UsageChanged(this, random.Next(1, 100));
    }
}

The problem with the code above is that if an exception occurs in one of the event handlers (and it does occur in the second event handler), than subsequent event handlers do not get notified.

NOTE: the event handler delegates are executed in sequential order but the CLI does not guarantee that the delegates are executed in the order in which they have been added.

So, in order to avoid the exception that occur in one event handler (subscriber) interfere with the notification of other event handlers (subscribers), the preferred solution would be to manually retrieve the event handlers (subscribers) and notify them one by one:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var cpu = new CPU();

        cpu.UsageChanged += (sender, percentage) => 
            Console.WriteLine("Handler1: Cpu Usage: {0} %", percentage);

        cpu.UsageChanged += (sender, percentage) =>
        {
            Console.WriteLine("Handler2: Cpu Usage: {0} %", percentage);
            throw null; 
        };

        cpu.UsageChanged += (sender, percentage) =>
            Console.WriteLine("Handler3: Cpu Usage: {0} %", percentage);

        cpu.DoWork();
    }
}

class CPU
{
    public event EventHandler<int> UsageChanged = delegate { };

    public void DoWork()
    {
        var random = new Random();
        int percentage = random.Next(1, 100);

        var exceptions = new List<Exception>();

        foreach (Delegate subscriber in UsageChanged.GetInvocationList())
        {
            try
            {
                subscriber.DynamicInvoke(this, percentage);
            }
            catch (Exception e)
            {
                exceptions.Add(e);
            }
        }

        if (exceptions.Count > 0)
        {
            throw new AggregateException(exceptions);
        }
    }
}
Advertisements

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