Click here to Skip to main content
Email Password   helpLost your password?

Introduction

The goals of this articles is to present very short (as possible) an overview about delegates and events
The "hot" shots of this article are :

Delegates

What is a delegate ? A delegate is an object who report a method.When we create a delegate, we actually create an object who will memorize a reference to a method.This method can appeal through this reference.Even if a method is not an object, this method will have a physical location inside of the memory.
The Delegate class is the base class for delegate types. However, only the system and compilers can derive explicitly from the Delegate class or from the MulticastDelegate class. It is also not permissible to derive a new type from a delegate type. The Delegate class is not considered a delegate type; it is a class used to derive delegate types.

Most languages implement a delegate keyword, and compilers for those languages are able to derive from the MulticastDelegate class; therefore, users should use the delegate keyword provided by the language.

The declaration of a delegate type establishes a contract that specifies the signature of one or more methods. A delegate is an instance of a delegate type that has references to:

Now let's see an simple example of delegates :

 //** simple example of delegates
using System;

//** declaring a delegate
delegate string strMod(string str);

class DelegateTest
{
    //** we replace spaces with lines
    static string replaceSpaces(string a)
    {
        Console.WriteLine("Replace spaces with lines.");
        return a.Replace(' ', '-');
    }
    //** delete spaces
    static string removeSpaces(string a)
    {
        string temp = "";
        int i;

        Console.WriteLine("Delete spaces.");
        for (i = 0; i < a.Length; i++)
            if (a[i] != ' ')
                temp += a[i];
        return temp;
    }
    //** string reverse
    static string reverse(string a)
    {
        string temp = "";
        int i, j;

        Console.WriteLine("Reverse string.");
        for(j = 0; i = a.Length - 1; i >=0; i--; j++)
            temp += a[i];
        return temp;
    }

    public static void Main()
    {
        //** Building delegates
        strMod strOp = new strMod(replaceSpaces);
        string str;

        //** calling methods using delegates
        str = strOp("This is a test.");
        Console.WriteLine("The result string is : " + str);
        Console.WriteLine();

        strOp = new strMod(removeSpaces);
        str = strOp("This is a test.");
        Console.WriteLine("The result string is : " + str);
        Console.WriteLine();

        strOp = new strMod(reverse);
        str = strOp("This is a test.");
        Console.WriteLine("The result string is : " + str);
    }
}

The result of this code will be :

Replace spaces with lines. 
The result string is : This-is-a-test

Delete spaces.
The result string is : Thisisatest

Reverse string.
The result string is : tsest a si siht

Now let's study toghether a little the code to understand much better how the things are going :

strMod strOp = new strMod(replaceSpaces); 
str = strOp("This is a test.");

Because strOp refer replaceSpaces() method, this will the invoked method.Then to strOp will be added an reference to removeSpaces method, after, strOp delegates is called one more time.This time the invoked method will be removeSpaces().Final to strOp will add a reference to reverse(), after the delegate is called .This will establish a call of reverse() method.

In the next example, is the same example like above one, the single difference is that the operations over the strings are encapsulated into a class named StringOps :

//** delegates can refer instance method
using System;

//** declaring an delegate
delegate string strMod(string str);

class StringOps
{
    //** replace spaces with lines
    public string replaceSpaces(string a)
    {
        Console.WriteLine("Replace spaces with lines.");
        return a.Length(' ', '-');
    }
    //** deleting spaces
    public string removeSpaces(string a)
    {
        string temp = "";
        int i, j;

        Console.WriteLine("Deleting spaces.");
        for(i = 0; i < a.Length; i++)
            if(a[i] != ' ')
                temp += a[i];
    }
    //** reverse the string
    public string reverse(string a)
    {
        string temp = "";
        int i, j;

        Console.WriteLine("Reverse the string.");
        for(j = 0, i = a.Length - 1; i >= 0; i--, j++)
            temp += a[i];

        return temp;
    }
    class DelegateTest
    {
        public static void Main()
        {
            StringOps so = new StringOps();

            //** building delegates
            strMod strOp = new strMod(so.replaceSpaces);
            string str;

            //** calling methods using delegates
            str = strOp("This is a test.");
            Console.WriteLine("The result string is : " + str);
            Console.WriteLine();

            strOp = new strMod(removeSpaces);
            str = strOp("This is a test.");
            Console.WriteLine("The result string is : " + str);
            Console.WriteLine();

            strOp = new strMod(reverse);
            str = strOp("This is a test.");
            Console.WriteLine("The result string is : " + str);
        }
    }
}

This program produced the same result like the first one, but in this case delegates refer methods using an instance of class StrOps.

Multicasting

One of the most interesting facilities that delegates offer is the ability of multicasting.t times, it is desirable to call two (or more) implementing methods through a single delegate. This becomes particularly important when handling events (discussed later in this chapter).
The goal is to have a single delegate that invokes more than one method. For example, when a button is pressed, you might want to take more than one action.Two delegates can be combined with the addition operator (+). The result is a new multicast delegate that invokes both of the original implementing methods.

In simple terms, the multicasting term designate the ability to create a methods chain who will be automatically called when the delegate will be invoked.A chain like this is very simple to create.Is enough to create an instance of a delagate and then using the += operator we can add methods in chain.To delete or eliminate a method from chain you have to use -=.

Nota bene !!! Also we can use the +, - and = , independent to add and decrease delegates, but += and -= are more used.The single restriction is that the multicast delegates has to return a result of void type.

Down, we have an example of multicastin.This restriction rewrite the two examples above, the single modification is the return type by the methods with strings at void and using a ref parameter to return the modified string in the module that has been called.

//** Present the multicasting term
using System;

//** delegate declaring
delegate void strMod(ref string str);

class StringOps
{
    //** we replace spaces with lines
    static string replaceSpaces(ref string a)
    {
        Console.WriteLine("Replace spaces with line.");
        Console.WriteLine(' ', '-');
        return a.Replace(' ', '-');
    }
    //** delete spaces
    static string removeSpaces(ref string a)
    {
        string temp = "";
        int i;

        Console.WriteLine("Delete spaces.");
        for (i = 0; i < a.Length; i++)
            if (a[i] != ' ')
                temp += a[i];
        return temp;

        a = temp;
    }
    //** string reverse
    static string reverse(ref string a)
    {
        string temp = "";
        int i, j;

        Console.WriteLine("Reverse string.");
        for(j = 0; i = a.Length - 1; i >=0; i--; j++)
            temp += a[i];
        return temp;

        a = temp;
    }

    public static void Main()
    {
        //** building delegates
        strMod strOp;
        strMod replaceSp = new strMod(replaceSpaces);
        strMod removeSp = new strMod(removeSpaces);
        strMod reverseStr = new strMod(reverse);
        string str = "This is a test";

        //** creatin a multicast delegate
        strOp += replaceSp;
        strOp += reverseStr;

        //** multicast delegate call
        strOp(ref str);
        Console.WriteLine("The result string is : " + str);
        Console.WriteLine();

        //** remove replacing with lines and add deleting of spaces
        strOp -= replaceSp;
        strOp += removeSp;
        str = "This is a test";    //** reinitialize the string

        //** multicast delegate call
        strOp(ref str);
        Console.WriteLine("The result string is : " + str)
        Console.WriteLine();
    }
}

This program will show on screen the following messages :

Replace spaces with line.
Reverse the string.
The result string is : tsest a si sihT

Reverse the string.
Delete spaces.
The result string is : tsestasisihT. 

Let's examine a little the code without going to deep in it.We can see that in the Main() method , are created four instances having delegate type.The next three delegates refer each a specific method who modify the characters string.After that a multicast delegate is created who call removeSpaces() and reverse() methods.This is made in the next line :

strOp = replaceSp;
strOp += reverseStr;

First, to strOp we appeal an reference to replaceSp. Using after the += operator, we add also the reverseStr delegate.When strOp is invoked , both methods will be called, replacing spaces with lines and reversing the string.
Forward, the delegate is eliminated from the chain, using the next line

strOp -= replaceSp;

after we add removeSp, using the line

strOp += removeSp;

We invoked one more time the strOp delegate.This time the string will be reversed and the spaces will be deleted.

Events

Event is another facility of C# language that is very important.An event show when an action take place.The events are members entity of a class.The general form of declaration is :

event event-delegate object-name;

Let's explain a bit the general form : event-delegate represent the name of the delegate that is used for event treatment and object-name is the name of the event instance that is created.Let's start by showing a simple example :

//** A simple case of using events
using System;

//** declare an delegate for an event
delegate void MyEventHandler();

//** declare an event class
class MyEvent
{
    //** declare the event
    public event MyEventHandler activate;

    //** the method that is called on event loading
    public void fire()
    {
        if (activate != NULL)
            activate();     //** loading the event
    }
}
class EventDemo
{
    static void handler()
    {
        Console.WriteLine("The event has been made.");
    }
    public static void Main()
    {
        MyEvent evt = new MyEvent();    //** create the instance on an event
        //** add the routine of treatment in chain    
        evt.activate += new MyEventHandler(handler); 
        evt.fire(); //** generating of an event
    }
} 

This program will show :

The even has been made. 

The next example will show an multicast event.

The events can be multicas.This allows many objects to respond to an event notice.Down we have an example of multicast event.

//** A simple case of using an multicast event
using System;

//** declare an delegate for an event
delegate void MyEventHandler();

//** declare an event class
class MyEvent
{
    //** declare the event
    public event MyEventHandler activate;

    //** the method that is called on event loading
    public void fire()
    {
        if (activate != NULL)
            activate();     //** loading the event
    }
}
class X
{
    public void Xhandler()
    {
        Console.WriteLine("Event received by an X object");
    }
}
class Y
{
    public void Yhandler()
    {
        Console.WriteLine("Event received by an Y object");
    }
}
class EventDemo
{
    static void handler()
    {
        Console.WriteLine("Event received by EventDemo");
    }
    public static void Main()
    {
        MyEvent evt = new MyEvent();    //** create the instance on an event
        X xOb = new X();
        Y yOb = new Y();

        //** we add the treatment routines to the event list
        evt.activate += new MyEventHandler(handler);
        evt.activate += new MyEventHandler(xOb.Xhandler);
        evt.activate += new MyEventHandler(yOb.Yhandler);

        evt.fire(); //** generating of an event
        Console.WriteLine();

        //** delete a treatment routine
        evt.activate -= new MyEventHandler(xOb.Xhandler);
        evt.fire();
    }
}

The program will show :

Event received by EventDemo
Event received by an X object
Event received by an Y object

Event received EventDemo
Event received an Y object.

The next program will show you how to distribute an event to three instances having X type.The code is :

 //** Events are fated to instances not classes
using System;

//** declare an delegate for an event
delegate void MyEventHandler();

//** declare an event class
class MyEvent
{
    //** declare the event
    public event MyEventHandler activate;

    //** the method that is called on event loading
    public void fire()
    {
        if (activate != NULL)
            activate();     //** loading the event
    }
}
class X
{
    int id;

    public X(int x)
    {
        id = x;
    }
    public void Xhandler()
    {
        Console.WriteLine("An event received by an instance " + str);
    }
}

class EventDemo
{
    public static void Main()
    {
        MyEvent evt = new MyEvent();    //** create the instance on an event
        X o1 = new X(1);
        X o2 = new X(2);
        X o3 = new X(3);

        //** we add the treatment routines to the event list
        evt.activate += new MyEventHandler(o1.Xhandler);
        evt.activate += new MyEventHandler(o2.Xhandler);
        evt.activate += new MyEventHandler(o3.Xhandler);
      
        evt.fire(); //** generating of an event
       }
}

This program will show :

An event received by instance 1
An event received by instance 2
An event received by instance 3

I will add to this articles, namespaces and how to use them toghether with delegates and events.

I hope this article has make a clear view and will be like a small guide through delegates and events.

HAPPY CODING !!!!!

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalmulticasting example
wAnAec
21:28 2 Sep '08  
You forget to modify return a result of void type.
By the way nice article.
GeneralEvents and threading
Pahan Menski
7:49 23 Jul '08  
Thanks for your article.

I'd like to make the following note. If you try to use your MyEvent class in multi-threaded environment where threads can detach methods from events, a problem may occur. So the more correct way to fire events in such applications is the following:

public void fire()
{
MyEventHandler _event = activate;
if (_event != NULL)
_event(); //** loading the event
}


Last Updated 18 Jul 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010