C# Delegates Explained - Delegates and their Generated MSIL Code
(Page 2 of 5 )
Let's look at our example from the ILDASM tool. Load the tool (type ildasm in the command prompt after you set the Path Environment) then open the Delegates.exe and expand the DelegateToMethod delegate type.

As you can see, the DelegateToMethod class is sealed, extends System.MulticastDelegate, and contains contains the methods .ctor (the Constructor), Invoke(), BeginInvoke() and EndInvoke(). If you click on any of those methods like Invoke() you will find no implementation, because as we said it's runtime implemented, as shown in the next screen shot:

The truly interesting code is in the Main method, so let's take a look at its MSIL Code:
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 115 (0x73)
.maxstack 3
.locals init ([0] class Delegates.DelegateToMethod aDelegate,
[1] class Delegates.DelegateToMethod mDelegate,
[2] class Delegates.DelegateToMethod dDelegate)
IL_0000: ldnull
IL_0001: ldftn int32 Delegates.Math::Add(int32,
int32)
IL_0007: newobj instance void Delegates.DelegateToMethod::.ctor(object,
native int)
IL_000c: stloc.0
IL_000d: ldnull
IL_000e: ldftn int32 Delegates.Math::Multiply(int32,
int32)
IL_0014: newobj instance void Delegates.DelegateToMethod::.ctor(object,
native int)
IL_0019: stloc.1
IL_001a: ldnull
IL_001b: ldftn int32 Delegates.Math::Divide(int32,
int32)
IL_0021: newobj instance void Delegates.DelegateToMethod::.ctor(object,
native int)
IL_0026: stloc.2
IL_0027: ldstr "Calling the method Math.Add() through the aDelegat"
+ "e object"
IL_002c: call void [mscorlib]System.Console::WriteLine(string)
IL_0031: ldloc.0
IL_0032: ldc.i4.5
IL_0033: ldc.i4.5
IL_0034: callvirt instance int32 Delegates.DelegateToMethod::Invoke(int32,
int32)
IL_0039: call void [mscorlib]System.Console::WriteLine(int32)
IL_003e: ldstr "Calling the method Math.Multiply() through the mDe"
+ "legate object"
IL_0043: call void [mscorlib]System.Console::WriteLine(string)
IL_0048: ldloc.1
IL_0049: ldc.i4.5
IL_004a: ldc.i4.5
IL_004b: callvirt instance int32 Delegates.DelegateToMethod::Invoke(int32,
int32)
IL_0050: call void [mscorlib]System.Console::WriteLine(int32)
IL_0055: ldstr "Calling the method Math.Divide() through the dDele"
+ "gate object"
IL_005a: call void [mscorlib]System.Console::WriteLine(string)
IL_005f: ldloc.2
IL_0060: ldc.i4.5
IL_0061: ldc.i4.5
IL_0062: callvirt instance int32 Delegates.DelegateToMethod::Invoke(int32,
int32)
IL_0067: call void [mscorlib]System.Console::WriteLine(int32)
IL_006c: call string [mscorlib]System.Console::ReadLine()
IL_0071: pop
IL_0072: ret
} // end of method DelegateApp::Main
the IL opcode ldnull loads a null value on the stack because, as we have said before, the encapsulated method is a static method and a null value is passed to the constructor of the delegate. The next is the ldftn opcode which pushes an unmanaged pointer to the method Math.Add. the newobj allocates memory for the object (the delegate object) then calls the .ctor (the Constructor). The delegate is calling its referenced method through the following instruction
IL_0034: callvirt instance int32 Delegates.DelegateToMethod::Invoke(int32,
int32)
As you can see, the method Invoke(int32, int32) is called which in turn calls the Math.Add() method. Let's modify our example to work with instance methods.
Next: Delegates on Instance Methods >>
More C# Articles
More By Michael Youssef