How delegates work (in the background)?

2019-01-18 14:04发布

问题:

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?

回答1:

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 typical TypeConverter usage:

using System;
using System.Reflection;
static class Program { // formatted for space
    static void Main() {
        // do this in a loop to see benefit...
        int i = Test<int>.Parse("123");
        float f = Test<float>.Parse("123.45");
    }
}
static class Test<T> {
    public static T Parse(string text) { return parse(text); }
    static readonly Func<string, T> parse;
    static Test() {
        try {
            MethodInfo method = typeof(T).GetMethod("Parse",
                BindingFlags.Public | BindingFlags.Static,
                null, new Type[] { typeof(string) }, null);
            parse = (Func<string, T>) Delegate.CreateDelegate(
                typeof(Func<string, T>), method);
        } catch (Exception ex) {
            string msg = ex.Message;
            parse = delegate { throw new NotSupportedException(msg); };
        }
    }
}


回答2:

When you define your delegate

internal delegate void Feedback(Int32 value);

the compiler actually defines a complete class that looks something like this:

internal class Feedback : System.MulticastDelegate {  
   // Constructor  
   public Feedback(Object object, IntPtr method);  

   // Method with same prototype as specified by the source code  
   public virtual void Invoke(Int32 value);  

   // Methods allowing the callback to be called asynchronously  
   public virtual IAsyncResult BeginInvoke(Int32 value,  AsyncCallback callback, Object object);  

   public virtual void EndInvoke(IAsyncResult result);  
}

Source: Jeffrey Richter - CLR via C#, chapter 17



回答3:

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 and Delegate.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 type System.IntPtr). A method pointer can be obtained (in CIL) via the ldftn or ldvirtftn (for virtual function calls) instructions.

These two pieces of information identify any method.

how can they be used efficiently?

What do you mean by that? Do you know about events or is your question more specialized?



回答4:

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.



回答5:

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.



回答6:

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):

[MethodImpl(0, MethodCodeType=MethodCodeType.Runtime)]
public virtual void Invoke(T obj);

The runtime use all the info internaly to compile a standard method call to the referenced method.



标签: c# delegates