Common Type System—CTS Support


Jump to: navigation, search
Visual C# Tutorials
.NET Framework Tutorials

Common Type System

© 2006 Wiley Publishing Inc.

CTS Support

The actual IL emitted shows some of the complexities of delegates in the underlying type system:

struct MyDelegate : System.MulticastDelegate
{
   public MyDelegate(object target, IntPtr methodPtr);
   private object target;
   private IntPtr methodPtr;
   public internal void Invoke(int x, int y);
   public internal System.IAsyncResult 
      BeginInvoke(int x, int y,
      System.IAsyncCallback callback, object state);
   public internal void EndInvoke
      (System.IAsyncResult result);
}

The constructor is used to form a delegate over a target object and a function pointer. The Invoke, BeginInvoke, and EndInvoke methods implement the delegate invocation routine and are marked as internal (i.e., runtime in IL) to indicate that the CLR provides the implementation; their IL bodies are left blank. Invoke performs a synchronous invocation, while the BeginInvoke and EndInvoke functions follow the Asynchronous Programming Model pattern for asynchronous method invocation.

Notice first that the MyDelegate type breaks one of the rules discussed above, namely that structs cannot derive from types other than ValueType. Delegates have special support in the CTS, so this is allowed. Also notice that MyDelegate derives from MulticastDelegate; this type is the common base for all delegates created in C# and supports delegates that have multiple targets. The section on events describes why this is useful. MulticastDelegate also defines a large set of additional methods that we will ignore for now and that have been omitted from the definition above.

To form a delegate over a target, the IL uses MyDelegate’s constructor. The constructor accepts an object for input, which is the this pointer to be passed during method invocation (or null for static methods), and an IntPtr representing the managed function pointer to the CLR method. This is a C-style function pointer that points at the just-in-time compiled code in the runtime. The Invoke signature matches that of the delegate we defined, and the CLR ensures that both statically and dynamically the function pointer contained within the delegate matches this signature. The CreateAndInvoke code above emits the following sequence of IL:

ldarg.0 // loads the ‘thisfor CreateAndInvoke’s method
ldftn void Foo::PrintPair(int32, int32)
newobj instance void MyDelegate::.ctor(object, native int)
ldc.i4.s 10
ldc.i4.s 20
callvirt instance void MyDelegate::Invoke(int32, int32)
ret

Notice that it uses the ldftn instruction to load a function pointer to the PrintPair method and then uses the Invoke method defined on MyDelegate to invoke the underlying method. This has the result of indirectly calling the code for PrintPair, passing the values 10 and 20 for its arguments.


Previous_Page_.gif Next_Page_.gif





Personal tools