Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C#

Delegate Behind the Scenes

Rate me:
Please Sign up or sign in to vote.
4.88/5 (21 votes)
23 Mar 2009CPOL3 min read 35.6K   56   6
Describing complete class of delegate and asynchronous processing

Audience

This article is intended for people who have basic knowledge about delegates in C#.

Introduction

We all know about the word delegate in the .NET world. But what will the compiler do when seeing the word delegate in your program. The compiler and the CLR do a lot of behind the scenes processing to hide the complexity. I'll focus on how the compiler and the CLR work together to implement delegates. This article will explain to you about the complete class of delegate and the asynchronous processing performed by the delegate.

Using the Code

C#
public delegate void MyDelegate(int intValue);

The compiler actually defines a complete class that looks something like this:

C#
class MyDelegate : System.MulticastDelegate
{
    //constructor
    public  MyDelegate(Object object, Inptr method);

    //same prototype as specified in the source code 
    public virtual void Invoke(Int32 intValue);

    //delegate methods can be called asynchronously 
    public virtual IAsyncResult BeginInvoke(Int32 intValue, 
			AsyncCallback callback, object object);

    public virtual void EndInvoke(IAsyncResult result);
}

Image 1

ILdasm.exe displaying the metadata produced by the compiler for the delegate.

The class defined by the compiler has four methods:

  • constructor
  • Invoke method
  • BeginInvoke method
  • EndInvoke method

Invoke method is used to call the target method in the same thread. It is a synchronous process. I will explain to you about the BeginInvoke and EndInvoke methods later in this article. Before that, we want to know about how the methods (static and instance) are pointed internally in delegate, probably this is the most significant feature in delegates. There are three non public fields: 

  1. _target
    When a delegate object wraps a static method, this field is null. When the delegate objects wraps the instance method, this field refers to the object. 
  2. _methodptr
    It is used to identify the method that is to be called back. 
  3. _invocationlist
    This field is usually null, it can refer to an array of delegates when building a delegate chain.
C#
MyDelegate objStatic     =  new MyDelegate(Class.StaticMethod);
MyDelegate objInstance =  new MyDelegate(new Class().InstanceMethod);

Image 2

Image 3

The _target field holds the System.Object type. A reference to the object is passed for the constructor's object parameter, and a special intptr value that identifies the method is passed for the method parameter. For static methods, null is passed for the object parameter. Inside the constructor, these two arguments are saved in the _target and _methodptr private fields, respectively.

Internally, the combine method sees that objChain already refers to a delegate object, so combine will construct a new delegate object. This new delegate object initializes its private _target and _methodptr fields to values that are out of scope here. What is important is that the _invocationlist field is initialized to refer to an array of delegate objects. The first element of the array (index 0) will be initialized to refer to the delegate that wraps the static method. The second element of the array (index 1) will be initialized to refer to the delegate that wraps the Instance method.

C#
MyDelegate objStatic1     =  new MyDelegate(Class.StaticMethod1);
MyDelegate objInstance2 =  new MyDelegate(new Class().InstanceMethod2);

MyDelegate objChain = null;
objChain = (MyDelegate) Delegate.Combine( objChain, objStatic1);
objChain = (MyDelegate) Delegate.Combine( objChain, objInstance2);    

Image 4

Asynchronous Delegates

Delegates can call the methods in an asynchronous manner. If the BeginInvoke method is called, then the CLR will queue the request and return immediately to the main thread. The target method will be called on a thread from the thread pool. The main thread can perform parallel execution to the target method. BeginInvoke method has three parameters:

  1. Input parameter
  2. AsyncCallBack delegate instance
  3. Async State information
C#
objDel.BeginInvoke(5,new AsyncCallback(MyCallback),"Result From Main Program");

The last two parameters are used to provide a callback mechanism that will be invoked when the target method completes. This is called AsyncCallBack delegate.

C#
delegate void AsyncCallback( IAsyncResult ar );

If the callback was not specified in the BeginInvoke then the EndInvoke is used in the original thread. It is used to obtain the return value for the asynchronous processing. If the callback was present, then the EndInvoke is placed in the callback method.

Below is the sample program for Asynchronous delegate:

C#
public delegate int MyDelegate(int intX);

class Program
{
    static void Main(string[] args)
    {
        MyClass objClass = new MyClass();
        MyDelegate objDel = new MyDelegate(objClass.MyMethod);

        //Asynchronous processing begins here
        IAsyncResult AsyncRes = objDel.BeginInvoke
		(5, new AsyncCallback(MyCallBack), "State info from main thread");

        Console.WriteLine("From main thread ");

        Console.ReadLine();
    }

    public static void MyCallBack(IAsyncResult ar)
    {
        AsyncResult Result = (AsyncResult)ar;
        MyDelegate objDel = (MyDelegate)Result.AsyncDelegate;
        int intResult = objDel.EndInvoke(ar);
        Console.WriteLine("Output from callback: " + intResult);

        //state information from the main thread
        string strMessage = (string)ar.AsyncState;
        Console.WriteLine(strMessage);
    }
}

class MyClass
{
    public int MyMethod(int intX)
    {
        Thread.Sleep(10000);
        return (intX * intX);
    }
}        

Output

Image 5

Conclusion

Delegate is an object which refers to methods. It can be used in asynchronous or synchronous processes by running the methods in another threads. The asynchronous process is mainly useful for background processing like mailing, database transaction, etc. so the user may not wait until the operation completes.

History

  • 23rd March, 2009: Initial post

License

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


Written By
Software Developer (Senior)
India India
Working as a software engineer with 5+ Years of experience in Web Based applications using Microsoft Technologies.

Comments and Discussions

 
GeneralGood One Pin
r_anand_kumar23-Mar-09 3:46
r_anand_kumar23-Mar-09 3:46 

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

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