Delegates and Events – Part 2.

Events

Events are always implemented with delegates in C#. Publishing class defines a delegate, the subscribing class first creates a method that matches the delegate signature and then creates an instance of the delegate type encapsulating that method. Everytime an event is raised, the subscribing class’s methods are invoked through the delegate.

Event handler is a method that handles an event.

In .NET Framework event handlers are always return void and have two parameters. The first parameter is the publishing object a.k.a. source, the second parameter is an object derived from EventArgs. You should always follow this design pattern.

Let’s create a simple class called Clock. This class uses delegates to notify subscribers every time the time changes by one second. This delegate is going to be the SecondChangeHandler.

public delegate void SecondChangeHandler(object sender, TimeInfoEventArgs timeInformation);

As written in the first part of this post, this delegate encapsulate any method that returns void and has two parameters. First parameter is the object that raises the event, the second object (that will be derived from EventArgs) will contain additional information about the event.

public class TimeInfoEventArgs : EventArgs
{
    public int hour;
    public int minute;
    public int second;
    public TimeInfoEventArgs(int hour, int minute, int second)
    {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }
}

As you can see these additional information is the current hour, minute and second.

Now here’s the only method (with infinite loop) of the class Clock:

public void Run( )
{
    for (; ; )
    {
        Thread.Sleep(100);
        System.DateTime dt = System.DateTime.Now;

        if (dt.Second != second)
        {
            TimeInfoEventArgs timeInformation = new TimeInfoEventArgs(dt.Hour, dt.Minute, dt.Second);

            if (SecondChanged != null)
            {
                SecondChanged(this, timeInformation);
            }
        }

        this.second = dt.Second;
        this.minute = dt.Minute;
        this.hour = dt.Hour;
    }
}

As you may noticed, Clock class has three member variables: hour, minute and second. This method is simple and easy to understand: after sleep the method for 100ms, we get the current time and check if this second of current time is equal to the previous second. If no, we create the TimeInfoEventArgs object and if anyone subscribed, we’ll notify them. At the end we create the “previous second” (and minute and hour) for the next loop. Of course we need an instance of the SecondChangeHandler delegate. That is the:

public event SecondChangeHandler SecondChanged;

Now all we need is to create a subscriber class. Let’s say, this is the DisplayClock:

public class DisplayClock
{
    public void Subscribe(Clock theClock)
    {
        theClock.SecondChanged += new Clock.SecondChangeHandler(TimeHasChanged); //C# 1.0 version
        // theClock.SecondChanged += TimeHasChanged;// as mentioned in Part 1: use this (C# 2.0) version
    }

    public void TimeHasChanged(object theClock, TimeInfoEventArgs ti)
    {
        Console.WriteLine("Current Time: {0}:{1}:{2}", ti.hour.ToString( ), ti.minute.ToString( ), ti.second.ToString( ));
    }
}

When the Subscribe() method is invoked it creates a new SecondChangeHandler delegate, passing in its event handler: TimeHasChanged().

In previous example you subscribed to an event by invoking a new instance of the delegate. You can also subscribe without creating new instance of the delegate. This is called anonymous methods.

clock.SecondChanged += delegate( object theClock, TimeInfoEventArgs ti )
{
    Console.WriteLine( "Current Time: {0}:{1}:{2}",
      ti.hour.ToString( ), ti.minute.ToString( ), ti.second.ToString( ) );
};

This method has no name so it’s anonymous. This way you can invoke the method only through the delegate.
And here comes my favorite: the Lambda Expressions.
Since C# 3.0 you can subscribe to an event this way:

theClock.OnSecondChange +=
    (aClock, ti) =>
    {
        Console.WriteLine("Current Time: {0}:{1}:{2}",
                           ti.hour.ToString( ),
                           ti.minute.ToString( ),
                           ti.second.ToString( ));
    };

If your method doesn’t have any input parameters you should write empty parentheses:

...
( ) => 
{
    Console.WriteLine("No parameters here.");
};

It’s up to you which one you use. My suggestion for beginners:
– start with using the C# 2.0 version (remember: without the new keyword)
– later if your code allows, use anonymous method
– if you want to develop in other languages, try to stay at the final (C# 3.0) version.

If you have any question or need some example, just write me on the Contact form.