Click here to Skip to main content
Click here to Skip to main content

Tagged as

Go to top

Delegates, events, and namespaces using C#

, 18 Jul 2008
Rate this:
Please Sign up or sign in to vote.
delegates overview

Introduction

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

  • understanding the delegates concept
  • how to use events
  • creating conversion operators
  • goal of pre-processor
  • study of attributes

Delegates

What is a delegate? A delegate is an object which reports a method. When we create a delegate, we actually create an object which 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 the delegate types. However, only the system and the 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:

  • An instance method of a type and a target object assignable to that type.
  • An instance method of a type, with the hidden this parameter exposed in the formal parameter list. The delegate is said to be an open instance delegate.
  • A static method.
  • A static method and a target object assignable to the first parameter of the method. The delegate is said to be closed over its first argument.

Now, let's see a 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 the code together a little to better understand how things are going:

  • We declare a delegate named strMod which receives a parameter string and also returns a string.
  • In the class DelegateTest, we have declared three static methods; the signature of these static methods are the same as the signature of the delegates.
  • These methods make specific modifications on the strings that are received like parameters.
  • The method replaceSpaces() uses one of the methods of the class string named Replace() to replace the spaces with lines.
  • In Main(), we create a reference by type strMod named strOp. To this, we confer a reference to the replaceSpaces() method. Look at the following line:
  • strMod strOp = new strMod(replaceSpaces); 
  • Note how the method replaceSpaces() is sent like a parameter.
  • It uses the name of the method, the list of parameters is not specified.
  • We will see that the replaceSpace() method is called through the instance of the strOp delegate, like in the next line:
  • str = strOp("This is a test.");

Because strOp refers to the replaceSpaces() method, this will be the invoked method. Then, to strOp will be added a reference to the removeSpaces method; after that, the strOp delegate is called one more time. This time, the invoked method will be removeSpaces(). Finally, to strOp will be added a reference to reverse() after the delegate is called. This will establish a call to the reverse() method.

The next example is like the 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, the delegates refer to methods using an instance of the class StrOps.

Multicasting

One of the most interesting facilities that delegates offer is the ability of multicasting. 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 designates the ability to create a method chain which will be automatically called when the delegate will be invoked. A chain like this is very simple to create. It is enough to create an instance of a delegate, and then use the += operator, we can add methods to the chain. To delete or eliminate a method from the chain, you have to use -=.

Nota bene!!! We can use the +, -, and =, independent of adding and decreasing delegates, but += and -= are used more. The single restriction is that the multicast delegates have to return a result of type void.

Down, we have an example of multicasting. This restriction rewrites the two examples above. The single modification is the return type of the methods with strings as 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 too deep in it. We can see that in the Main() method are created four instances having a delegate type. The next three delegates refer each a specific method which modifies the characters string. After that, a multicast delegate is created which calls the removeSpaces() and reverse() methods. This is made in the next line:

strOp = replaceSp;
strOp += reverseStr;

First, to strOp we apply a reference to replaceSp. After the += operator, we also add the reverseStr delegate. When strOp is invoked, both methods will be called, replacing spaces with lines and reversing the string. The delegate is eliminated from the chain, using the next line:

strOp -= replaceSp;

after we add removeSp using the line:

strOp += removeSp;

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

Events

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

event event-delegate object-name;

Let's explain a bit the general form: event-delegate represents the name of the delegate that is used for the event treatment, and object-name is the name of the event instance that is created. Let's start by looking at 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 a multicast event.

The events can be multicast. This allows many objects to respond to an event notice. We have an example of a multicast event below.

//** 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 type X. 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 article information about namespaces and how to use them together with delegates and events.

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

Happy coding!!!!!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Marius Mihailescu
Instructor / Trainer ,,Titu Maiorescu'' University
Romania Romania
No Biography provided

Comments and Discussions

 
QuestionGetting Error While Executing code PinmemberMember 109231543-Jul-14 11:21 
Generalmulticasting example PinmemberwAnAec2-Sep-08 20:28 
You forget to modify return a result of void type.
By the way nice article.
GeneralEvents and threading PinmemberPahan Menski23-Jul-08 6:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140926.1 | Last Updated 18 Jul 2008
Article Copyright 2008 by Marius Mihailescu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid