Potty Little Details

Just another WordPress.com weblog

Demystifying Delegates

leave a comment »

On the surface, delegates seem easy to use: you define them using C#’s delegate keyword, you construct instances of them using the familiar new operator, and you invoke the callback using familiar “method call” syntax (except instead of a method name, you use the variable that refers to the delegate object).However, what’s really going on is quite a bit more complex . The compilers and the common language runtime (CLR) do a lot of behind-thescenes processing to hide the complexity. In this section, I’ll focus on how the compiler and the CLR work together to implement delegates.

Let’s start by reexamining this line of code:

public delegate void Feedback(

Object value, Int32 item, Int32 numItems);

When it sees this line, the compiler actually defines a complete class definition that lookssomething like this:

public class Feedback : System.MulticastDelegate {

// Constructor

public Feedback(Object target, Int32 methodPtr);

// Method with same prototype as specified by the source code

public void virtual Invoke(

Object value, Int32 item, Int32 numItems);

// Methods allowing the callback to be called asynchronously

public virtual IAsyncResult BeginInvoke(

Object value, Int32 item, Int32 numItems,

AsyncCallback callback, Object object);

public virtual void EndInvoke(IAsyncResult result);

}

The class defined by the compiler has four methods: a constructor, Invoke, BeginInvoke, and EndInvoke.In fact, you can verify that the compiler did indeed generate this class automatically by examining the resulting module with ILDasm.exe.In this example, the compiler has defined a class called Feedback that is derived from the System.MulticastDelegate type defined in the .NET Framework Class Library (FCL).(All delegate types are derived from MulticastDelegate.) The class is public because the delegate is declared as public in the source code. If the source code had indicated private or protected, the Feedback class the compiler generated would also be private or protected, respectively. You should be aware that delegate types can be defined within a class (as in the example, Feedback is defined within the Set class) or at global scope.Basically, because delegates are classes, a delegate can be defined anywhere a class can be defined.Because all delegate types are derived from MulticastDelegate, they inherit MulticastDelegate’s fields, properties, and methods. Of all these members, three private fields are probably most significant.

Field Type Description

_target System.Object Refers to the object that should be operated on when the callback method is called.This field is used for instance method callbacks.

_methodPtr System.Int32 An internal integer that the CLR uses to identify the method that is to be called back.

_prev System.MulticastDelegate Refers to another delegate object. This field is usually null.

Notice that all delegates have a constructor that takes two parameters: a reference to an object and an integer that refers to the callback method.A reference to the object is passed for the target parameter, and a special Int32 value (obtained from a MethodDef or MethodRef metadata token) that identifies the method is passed for the methodPtr parameter. For static methods, null is passed for the target parameter.Inside the constructor, these two parameters are saved in their corresponding private fields.In addition, the constructor sets the _prev field to null. This _prev field is used to create a linked list of MulticastDelegate objects.So, each delegate object is really a wrapper around a method and an object to be operated on when the method is called. The MulticastDelegate class defines two read-only public instance properties: Target and Method. Given a reference to a delegate object, you can query these properties. The Target property returns a reference to the object that will be operated on if the method is called back. If the method is a static method, Target returns null. The Method property returns a System.Reflection.MethodInfo object thatidentifies the callback method.You could use this information in several ways. For example, you could check to see whether a delegate object refers to an instance method of a specific type:

Boolean DelegateRefersToInstanceMethodOfType(

MulticastDelegate d, Type type) {

return((d.Target != null) && d.Target.GetType() == type);

}

You could also write code to check whether the callback method has a specific name (such as FeedbackToMsgBox):

Boolean DelegateRefersToMethodOfName(

MulticastDelegate d, String methodName) {

return(d.Method.Name == methodName);

}

Now that you know how delegate objects are constructed, let’s talk about how the callback method is invoked.

public void ProcessItems(Feedback feedback) {

for (Int32 item = 0; item < items.Length; item++) {

if (feedback != null) {

// If any callbacks are specified, call them.

feedback(items[item], item, items.Length);

}

}

}

Just below the comment is the line of code that invokes the callback method. It might seem as if I’m calling a function named feedback and passing it three parameters. However,there is no function called feedback. Again, because it knows that feedback is a variable that refers to a delegate object, the compiler generates code to call the delegate object’s Invoke method. In other words, the compiler sees this:

feedback(items[item], item, items.Length);

But the compiler generates code as though the source code said this:

feedback.Invoke(items[item], item, items.Length);

You can verify that the compiler produces code to call the delegate type’s In-voke method by using ILDasm.exe to examine the code for the ProcessItems method. More details check out dot net programming by Jeffery Ritcher

Advertisements

Written by oneil

September 13, 2008 at 2:24 am

Posted in C#

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: