How do delegates work in c# behind the scenes and how can they be used efficiently?
EDIT: I know how they work on the surface(they are basically function pointers and allow callback methods with certain signatures to be invoked using their address). What I need to know is how the CLR actually implements them internally. What exactly happens behind the scenes when you define a delegate and when you invoke a callback method using the delegate object?
C# compiler generates a full blown class when you create a delegate. This class holds a list of function references, as Konrad mentioned. The nice thing about delegates is that they provide you with easy way to execute the task asynchronously with notification callback. What this means is that you can be notified when your background operation completes. Threadpool doesn't provide this feature. Delegates are a vast topic and I find Jeff Richter's (CLR via C#) and Albahari (C#3) books of particular help.
The first part of the question is relatively easy: delegates store a list of function pointers. If you invoke a delegate, it calls all the function pointers in that internal list. Adding and removing a receiver (via
Delegate.Combine
andDelegate.Remove
) amounts to adding to and removing from that list.For more low-level information, refer to ECMA-335 (the CLI standard), section II.14.5 (Method pointers) and II.14.6 (Delegates). In particular, note that a delegate consists of an instance pointer (of type
System.Object
) and a method pointer (of typeSystem.IntPtr
). A method pointer can be obtained (in CIL) via theldftn
orldvirtftn
(for virtual function calls) instructions.These two pieces of information identify any method.
What do you mean by that? Do you know about events or is your question more specialized?
When you define your delegate
the compiler actually defines a complete class that looks something like this:
Source: Jeffrey Richter - CLR via C#, chapter 17
Re efficiency - it isn't clear what you mean, but they can be used to achieve efficiency, by avoiding expensive reflection. For example, by using
Delegate.CreateDelegate
to create a (typed) pre-checked delegate to a dynamic/looked-up method, rather than using the (slower)MethodInfo.Invoke
.For a trivial example (accessing the static
T Parse(string)
pattern for a type), see below. Note that it only uses reflection once (per type), rather than lots of times. This should out-perform either reflection or typicalTypeConverter
usage:C# delegates are objects (check the System.Delegate class) that encapsulate a reference to an object and a method pointer. They can also have a null reference to object to represent a call to a static method.
When invoking the delegate with arguments, the delegate crafts a call to the referenced method on referenced object with specified arguments.
A compiled delegate Invoke method is directly handled by the runtime (as visible with Reflector):
The runtime use all the info internaly to compile a standard method call to the referenced method.
Delegates in C# are lists of method pointers. I.e. they store references to code, and you can invoke the methods via the pointers. This is useful in many cases. The common example is for event handlers where delegates are used to implement a publisher/subscriber pattern.