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

A Study of Delegates

By , 19 Jul 2006
 

Introduction

Many of us already have some idea of delegates. But let's go deep inside and examine how the CLR/runtime and the compiler interprets the delegates, and what happens when you declare and manipulate delegates.

A delegate is a reference type, thus it does not hold the actual value, rather it holds the address of an object residing somewhere in the heap. To make the understanding of delegates simple, compilers represent the delegates in a different way than how it is interpreted by the CLR/runtime. We will first study how the compiler exposes delegates, and then we will jump into some ground realities of delegates from the CLR/runtime perspective.

Delegates and .NET Compilers

To make life simpler, most .NET compilers symbolize delegates as pointers to a function, just like the function pointers we have in C++. Thus, in C#, you declare delegates as follows:

public delegate void MyDelegate (int someParam, string anotherParam);

From a C# compiler perspective, MyDelagate is a delegate that could hold the address of a function that has the similar signature.

The ability of holding the address of a function makes delegates ideal for:

  1. Callback functionality
  2. Event modeling
  3. Having more than one implementation against a method

Though the C# compiler exposes delegates as reference types, you could not instantiate the delegate by using the new operator; rather delegates could be instantiated by:

  1. Providing the name of the method to the delegate. These types of delegates are known as "Named Delegates".
    void DoSomething(int someParam, string anotherParam)
    {
        //Method implementation
    }
    
    MyDelegate del = DoSomething;
    //del is a Named Delegate holding 
    //the address of function DoSomething.
  2. Providing the implementation of the method to the delegate. These type of delegates are known as "Anonymous Delegates".
    del = delegate(int someParam, string anotherParam)
          { //Method implementation };

Invoking of named or anonymous delegates is same as calling the function:

Del (29, "some value");

Named Delegates

Named delegates could hold the address of instance methods as well as the address of static methods. If the return type of a method is inheriting from the return type defined in the delegate, then the delegate is known as a Covariance Delegate. If the parameters of the methods are the base types of the parameters defined in the delegate, then the delegate is known as a Contravariance Delegate.

public delegate ICollection MyDelegate (int someParam, 
                                 string anotherParam); 

IList DoSomething()
{
    //Method implementation
}

MyDelegate del = DoSomething;

//As IList is child of ICollection thus, 
//Del is covariance delegate.
public delegate ICollection MyDelegate (IList param);

IList DoSomething(ICollection param)
{
    //Method implementation
}

MyDelegate del = DoSomething;

//As IList is child of ICollection thus, 
//Del is contravariance delegate.

Anonymous Delegates

If an anonymous delegate is referring to some local variables, then the life of that variable would be extended to the life of that delegate.

public delegate void MyDelegate (int someParam, string anotherParam); 

MyDelegate del
void DoSomething()
{
    int n;
    del = delegate(int someParam, string anotherParam)
    { 
        n++;
    }    
}
//In above example life of local variable n 
//would be same as life of anonymous delegate del.

Delegates and the CLR/Runtime

.NET compilers have made our life easy in handling delegates. In reality, there is neither any concept of pointers to a function nor any significance to the word "delegate" in the CLR/runtime. Rather, the CLR provides an abstract class System.Delegate that holds the reference of a static method or class instance and the instance method of that class. The System.Delegate has two properties.

  • Target: Holds the reference of an instance on which the current delegate invokes the instance method. If the method is a static method, this property holds a null value.
  • Method: Holds the instance of the MethodInfo class for the method represented by the delegate.

The delegate also exposes the DynamicInvoke function to call the method represented by the Method property. This function takes an array of objects that are the arguments to pass to the target method. If the target method does not take any arguments, the parameter to the DynamicInvoke function would be null.

The CLR also exposes an abstract class System.MultiCastDelegate that inherits from System.Delegate. System.MultiCastDelegate maintains a list, called the Invocation List, of a delegate object. When a multicast delegate is invoked, all the delegates in the invocation list are called synchronously. The System.MultiCastDelegate exposes the Combine method to add delegates to the invocation list.

When you define a delegate in C#, a new class with the name of the delegate inheriting from System.MultiCastDelegate is created by the C# compiler.

public delegate ICollection MyDelegate (IList param);

The above statement causes a a new class to be added in your assembly by the C# compiler.

public class MyDelegate : System.MultiCastDelegate

You can view this class by opening your assembly using the Ildasm utility.

When you assign a method to a delegate, an instance of the compiler generated class is created with the Target and Method as parameter to this class. In case the method is static, null is passed to the argument, Target.

As compiler generated classes are inheriting from System.MultiCastDelegate, thus delegate could hold the addresses of more than one method. C# exposes a simple method to add a method in the invocation list of underlying multiCast delegate object.

MyDelegate del;
del += DoSomething;
del += DoAnotherThing;

Internally, the C# compiler is calls the Combine method of the compiler-generated delegate class to add the methods to the invocation list.

When you invoke a delegate, C# internally calls the DynamicInvoke method of the compiler generated class. The compiler generated class also exposes methods to invoke the target methods asynchronously.

A delegate is known as an Open Instance Delegate if the Target is also provided at the time of invocation.

License

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

About the Author

Tariq A Karim
Software Developer (Senior) BGC Partners
United Kingdom United Kingdom
Member
Tariq Karim have over 9 years of experience in software engineering, design / architecture and technology management with strong background in Microsoft Technologies. Proven ability to manage complex environments, develop enterprise applications / services and align the information technology to solve business problems while managing cost and risks.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberyanghe16 Dec '10 - 15:57 
nice
Generalask for IsAlivememberolivianer17 Oct '08 - 2:17 
Hi,
 
would it not be better to ask for
 
ee.TargetReference.IsAlive
 
inside the Raise()-Method of the FastSmartWeakEvent ?
 
By the way the there is a little error on row 65, it should be:
 
if (argsParameter.ParameterType.IsSubclassOf(typeof(EventArgs)) == false)
 
But your article is really good stuff.
Greetings,
Oliver
QuestiondelegatesmemberGopiRajendran21 Jan '07 - 19:46 
What is the differents between delegates 1.1 and delegates2.0?
 
lj.prasanth

QuestionWhat about delegate in .NET 2memberAhmed.net7 Dec '06 - 2:22 
Aslamoo Aalikom
 
How are you
Execuse me What about using delegate in .NET 2 & how
please give an example
 

With best wishes
Ahmed
 
Ahmed

AnswerRe: What about delegate in .NET 2memberTariq Karim9 Dec '06 - 7:42 
Hi,
This topic covers all the features of delegate in 2.0 also. Let me give you an example. Anonymous delegate was introduced in .net 2.
 

Thanks
Tariq.
QuestionAbout Anonymous Delegatesmemberlenininy2k18 Sep '06 - 1:19 
Can you You Give me a Sample Example for Anonymous Delegates.........
 
Please.. i didn't understand given example....
 
Thanks & Regards
Lakshmi Narayana S
AnswerRe: About Anonymous DelegatesmemberTariq Karim19 Sep '06 - 9:32 
Anonymous delegate are similar to the normal delegate except that you define a function for the delegate. Rather in anonymous delegate, you define the implementation.
 
E.g if you want to handle the button click event, you can declare an anonymous delegate as follows:
 
button1.Click += delegate(System.Object o, System.EventArgs e)
{
System.Windows.Forms.MessageBox.Show("Oh...anonymous delegate is so simple.");
};

GeneralInvoking a delegatememberfcs3 Aug '06 - 0:23 
Good idea to write an article about how delegates work; however, there is a mistake at the end of your article: "When you invoke a delegate, C# internally calls the DynamicInvoke method of the compiler generated class."
 
This is not true, the C# compiler emits a call to the (runtime-implemented) Invoke method of the delegate. In fact, Invoke is quite fast (it's probably more or less a jump to the address stored within the delegate), wheres DynamicInvoke is pretty slow (because it has to extract the arguments from an object[] and needs to check that they are of the correct types).
 
Fabian
Questionre: Am I missing something?memberJames Wathen26 Jul '06 - 10:11 
Apparently I can't read! I am bouncing between 2003 and 2005. When I tried your code, I was using 2003. Works great in 2005. Thanks for your quick response!
 
Jim
QuestionAm I missing something ?memberJames Wathen26 Jul '06 - 6:32 
I thought you needed the new operator. I tried your "named delegate" example and had the following error:
 
"C:\WindowsApplication19\WindowsApplication19\Form1.cs(37): Method 'WindowsApplication19.Form1.DoSomething(int, string)' referenced without parentheses"
 
I put this in the namespace area:
 
public delegate void MyDelegate (int someParam, string anotherParam);
 
I added a DoSomething method with the appropriate signature.
 
I added a class level field : private MyDelegate del;
 
In the constructor method of the form I added the following line of code:
del = DoSomething;
 
When I try to compile the code I get the error message that I stated above.
 
I have used delegates before; but I am always trying to increase my understanding about them, that is why I read your article.

 
Jim

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 19 Jul 2006
Article Copyright 2006 by Tariq A Karim
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid