Delegate and events

Events

An event is the outcome of an action. There are two important terms with respect to events. The event source and the event receiver. The object that raises the event is called event source and the object that responds to the event is called event receiver. Did you observe a hitch in the above explanation?

O.K. my event source raises the event and my event receiver receives it, but what is the communication channel between them. Take the instance of you talking with a friend of yours over the telephone. Now you are the event source and your friend is the event receiver and the telephone cable is the communication channel. Similarly the communication channel between an event source and an event receiver is the delegate. The internals of events and their relationship to delegates would be dealt with in a later article. The explanation of events here is just to help the reader understand and visualize what exactly events are.

Delegates

Forget computers for a moment. Just think about delegates in the real world. Who are delegates? Delegates are people who represent a particular country or region or state in another country or region or state. Extend this same definition now to C#. In C#, delegates act as an intermediary between an event source and an event destination.
To be even precise delegates are similar to function pointers. They can be called as type safe function pointers. Delegates have other uses in addition to event handling. But this article would focus on describing delegates with respect to event handling. A delegate class used as an intermediary between an event source and event receiver is called an event handler.

Most programmers are used to passing data in methods as input and output parameters.
Imagine a scenario where you wish to pass methods around to other methods instead of data. Amazed! Read further.

Consider a scenario where you need to make a ‘business decision’ in your program, to make a decision you need data. To get data you need to call a method. However the method name is not known at design time. It will only be known at run time.

In this case you need to pass the unknown method as a parameter. The method that you are passing in is known as a Callback function. Call back functions are pointers to methods.

.NET implements the concept of function pointers using delegates.

  • Delegate wraps a method. Calling delegate results in calling the method.
  • Delegate is a type of object very similar to classes.
  • Delegate gives a name to a method signature. 




Where are Delegates used?

The most common example of using delegates is in events.
You define a method that contains code for performing various tasks when an event (such as a mouse click) takes place.
This method needs to be invoked by the runtime when the event occurs. Hence this method, that you defined, is passed as a parameter to a delegate.



namespace ConsoleApplication1
{
    public class MyClass
    {
      
        public  delegate void LogHandler(string message);
        public void Process(LogHandler logHandler)
        {
            if (logHandler != null)
            {
                logHandler("Process() begin");
            }

            if (logHandler != null)
            {
                logHandler("Process() end");
            }
        }
    }
    public class TestApplication
    {
        private   void Logger(string s)
        {
            Console.WriteLine(s);
            Console.ReadLine();
        }
        public void Logger2(string s)
        {
            Console.WriteLine(s);
            Console.ReadLine();
        }
        static void Logger1(string s)
        {
            Console.WriteLine(s);
            Console.ReadLine();
        }

        static void Main(string[] args)
        {
            TestApplication a = new TestApplication();
            MyClass myClass = new MyClass();
            MyClass.LogHandler myLogger = new MyClass.LogHandler(a.Logger);
            MyClass.LogHandler myLogger1 = new MyClass.LogHandler(Logger1);
            MyClass.LogHandler myLogger2 = new MyClass.LogHandler(a.Logger2);
            myClass.Process(myLogger);
            myClass.Process(myLogger1);
            myClass.Process(myLogger2);
        }
    }
}
http://www.akadia.com/services/dotnet_delegates_and_events.html


Types of Delegates

There are basically two types of delegates. Single Cast delegate and Multi Cast delegate. Let us first understand at the broader level the definition of both these delegates. 
  • A single cast delegate can call only one function.
  • A multi cast delegate is one that can be part of a linked list
  • The multi cast delegate points to the head of such a linked list. This means that when the multi cast delegate is invoked it can call all the functions that form a part of the linked list. Assume that i have several clients who would like to receive notification when a particular event occurs. Putting all of them in a multi cast delegate can help call all the clients when a particular event occurs.
  • To support a single cast delegate the base class library includes a special class type called System.Delegate
  • To support multi cast delegates the base class library includes a special class type called SystemMultiCastDelegate.


A delegate in C# is similar to a function pointer in C or C++. Using a delegate allows the programmer to encapsulate a reference to a method inside a delegate object. The delegate object can then be passed to code which can call the referenced method, without having to know at compile time which method will be invoked.

In most cases, when we call a function, we specify the function to be called directly. If the class MyClass has a function named Process, we'd normally call it like this (SimpleSample.cs):
using System;

namespace NoDelegate
{
    public class MyClass
    {
        public void Process()
        {
            Console.WriteLine("Process() begin");
            Console.WriteLine("Process() end");
        }
    }

    public class Test
    {
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();
            myClass.Process();
        }
    }
}
That works well in most situations. Sometimes, however, we don't want to call a function directly - we'd like to be able to pass it to somebody else so that they can call it. This is especially useful in an event-driven system such as a graphical user interface, when I want some code to be executed when the user clicks on a button, or when I want to log some information but can't specify how it is logged.

Single Cast delegate

The signature of a single cast delegate is shown below. The letters in italics can be replaced with your own names and parameters.

public delegate Boolean  DelegateName (parm1, parm2)
 
When the compiler compiles the statement above, it internally generates a new class type. This class is called DelegateName and derives from System.Delegate. Just to make sure just check the ILDisassembler code to check that this is happening.
As an example let us create a single cast delegate named MyDelegate which would point to a function MyFunction. The code appears as below,

public delegate Boolean MyDelegate(Object sendingobj, Int32 x);

public class TestDelegateClass
{     
 Boolean MyFunction(Object sendingobj, Int32 x) 
 {           
  //Perform some processing           
  return (true);  
 }
        
 public static void main(String [] args)
 {
  //Instantiate the delegate passing the method to invoke in its constructor
  MyDelegate mdg = new MyDelegate(MyFunction);
            
  // Construct an instance of this class
  TestDelegateClass tdc = new TestDelegateClass();
               
  // The following line will call MyFunction
  Boolean f = mdg(this, 1);
       
 }
}
How does the above code work?
The System.Delegate contains a few fields. The most important of them are Target and Method.
The Target field identifies an object context. In the scenario above this would point to the TestDelegateClass being created. If the method to be invoked is a static method then this field will be null.
The Method field identifies the method to be called. This field always has some value. It is never null.
To the intelligent reader, if you observe the IL Disassembler code you would see that the constructor for MyDelegate contains two parameters. But in our case we are passing only one parameter? Any guesses on how this is done? Yeah you are right! It gets done internally by the compiler. The compiler resolves the call above to a call passing in the two parameters required. If you observe in C++ with managed extension, the object and the address of the function have to be passed explicitly. But in VB and C# we have done away with this with the compiler filling in the necessary details.
In the code sample above we saw,

Boolean f = mdg(this, 1);
When the compiler comes across this line, this is what happens,
  1. The compiler identifies that mdg is a delegate object.
  2. The delegate object has the target and method fields as described above.
  3. The compiler generates code that calls the Invoke method of the System.Delegate derived class i.e MyDelegate.
  4. The Invoke method internally uses the MethodInfo type identified by the delegate's Method field and calls the MethoidInfo's invoke method.
  5. The MethodInfo's invoke method is passed the delegates Target field which identifies the method and an array of variants which contains the parameters to the method to be called. In our case, the array of variants would be an Object and an Int32 value.
The above discussion would have made you clear about what happens internally when a method gets called through a Single Cast delegate.

Multi Cast delegate

The signature of a mutli cast delegate is shown below. The letters in italics can be replaced with your own names and parameters.

public delegate void DelegateName (parm1, parm2)
 
Whatever has been explained with respect to Single cast delegate holds good even in the context of a Multi Cast Delegate. There is a small addition here. Since a multi cast delegate represents a linked list, there is an additional field called prev which refers to another Multi Cast Delegate. This is how the linked list is maintained.
The return type if you have observed has changed from Boolean to void. Have you guessed the reason as to why it happens? The reason is that since several multi cast delegates get called consecutively we cannot wait to get the return value from each of these methods being called.
The code shown in the example for single cast delegate will work in the case of multi cast delegate too. The only difference is that the delegate signature needs to be changed, the method signature needs to be changed to return void instead of Boolean.
The power of multi cast delegates come in when you combine delegates to form a linked list. The Combine method is available in the System.Delegate class as a static method. The function signature as follows.

public static Delegate Combine(Delegate a, Delegate b);
 
What the above method does is that it combines the two delegates a and b and makes b's prev field point to a. It returns the head of the linked list. This in turn has to be type casted to our delegate type.
Similar to the Combine method we have a remove method which removes a delegate from the linked list and gives you the modifies smaller linked list with a pointer to the head. The signature of the remove method is as follows,
Collapse
public static Delegate Remove(Delegate source, Delegate value);
Here's a small sample that illustrates the use of a multi cast delegate,

using System;

class MCD1
{
    public void dispMCD1(string s)
    {
        Console.WriteLine("MCD1");
    }
}

class MCD2
{

    public void dispMCD2(string s)
    {
        Console.WriteLine("MCD2");
    }
}

 

public delegate void OnMsgArrived(string s);

class TestMultiCastUsingDelegates
{
    public static void Main(string [] args)
    {
        MCD1 mcd1=new MCD1();
        MCD2 mcd2=new MCD2();
        // Create a delegate to point to dispMCD1 of mcd1 object
        OnMsgArrived oma=new OnMsgArrived(mcd1.dispMCD1);

        // Create a delegate to point to dispMCD2 of mcd2 object
        OnMsgArrived omb=new OnMsgArrived(mcd2.dispMCD2);
 
        OnMsgArrived omc;
        // Combine the two created delegates. Now omc would point to the head of a linked list
        // of delegates
        omc=(OnMsgArrived)Delegate.Combine(oma,omb);
 
        Delegate [] omd;
         // Obtain the array of delegate references by invoking GetInvocationList()
        omd=omc.GetInvocationList();
 
         OnMsgArrived ome;
        // Now navigate through the array and call each delegate which in turn would call each of the
        // methods
        for(int i=0;i<omd.Length;i++)
        {
            // Now call each of the delegates
            ome=(OnMsgArrived)omd[i];
            ome("string");
        }
    }
}
The examples in this article would revolve around Multi Cast Delegates. It is essential that you have understood the basics of single cast and multi cast delegates before you proceed further.

Problem Scenario

The code below shows an example of adding a button to a Form. The button is associated with an event handler that handles whatever happens when the button is pressed. When the form is displayed and the button is pressed a message box showing "Button Clicked" will appear.
Compilation directions: Compile using
Collapse
csc /r:System.DLL;System.WinForms.DLL;Microsoft.Win32.Interop.DLL FormTest.cs
Collapse
/*
Creating a form and adding a button to it and associating the button with an event handler
*/
using System;
using System.WinForms;
public class FormTest : Form
{
    //Create a button
    private Button button1 = new Button();
    public static void Main (string [] args)
    {
        //Run the application
        Application.Run(new FormTest());
    }
    
    public FormTest()
    {
        //Set up the Form
        this.Text = "Hello WinForms World";
        //Set up the button
        button1.Text = "Click Me!";
        //Register the event handler
        button1.AddOnClick(new System.EventHandler(buttonClicked));
        //Add the controls to the form
        this.Controls.Add(button1);
    }
 
    //The event handling method
    private void buttonClicked(object sender, EventArgs evArgs)
    {
        MessageBox.Show("Button clicked");
    }
}
The topic of our discussion would be the routing of calls between the time when the click event is raised and the time when the method displaying "Button clicked" is displayed.