代表们如何工作(在后台)?

时间:2009-02-09 09:11:35

标签: c# delegates

代表们如何在幕后工作?如何有效地使用它们?

编辑:我知道它们是如何在表面上工作的(它们基本上是函数指针,并允许使用其地址调用某些签名的回调方法)。我需要知道的是CLR如何在内部实际实现它们。在定义委托时以及使用委托对象调用回调方法时,幕后究竟发生了什么?

6 个答案:

答案 0 :(得分:5)

提高效率 - 目前尚不清楚您的意思,但通过避免昂贵的反思,它们可以用来实现效率。例如,通过使用Delegate.CreateDelegate为动态/查找方法创建(类型化的)预先检查的委托,而不是使用(较慢的)MethodInfo.Invoke

对于一个简单的示例(访问类型的静态T Parse(string)模式),请参阅下文。请注意,它只使用一次反射(每种类型),而不是很多次。这应该超出反射或典型的TypeConverter用法:

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); };
        }
    }
}

答案 1 :(得分:4)

问题的第一部分相对容易:委托存储函数指针列表。如果调用委托,它将调用该内部列表中的所有函数指针。添加和删​​除接收者(通过Delegate.CombineDelegate.Remove)等于添加到该列表和从该列表中删除。

有关更多低级别信息,请参阅ECMA-335(CLI标准),第II.14.5节(方法指针)和II.14.6(代表)。特别要注意,委托包含一个实例指针(类型为System.Object)和一个方法指针(类型为System.IntPtr)。可以通过ldftnldvirtftn(用于虚函数调用)指令获取方法指针(在CIL中)。

这两条信息确定了任何方法。

  

如何有效地使用它们?

你是什么意思?您是否了解事件或您的问题更专业?

答案 2 :(得分:4)

定义代理时

internal delegate void Feedback(Int32 value);

编译器实际上定义了一个看起来像的完整类 像这样:

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);  
}

资料来源:Jeffrey Richter - CLR via C#,第17章

答案 3 :(得分:3)

C#中的委托是方法指针的列表。即它们存储对代码的引用,您可以通过指针调用方法。这在许多情况下很有用。常见示例是事件处理程序,其中委托用于实现发布者/订阅者模式。

答案 4 :(得分:1)

在创建委托时,C#编译器会生成一个完整的类。 正如Konrad所提到的,这个类包含一系列函数引用。 委托的好处是它们为您提供了与通知回调异步执行任务的简便方法。这意味着您可以在后台操作完成时收到通知。 Threadpool不提供此功能。 代表们是一个很大的话题,我发现Jeff Richter(CLR通过C#)和Albahari(C#3)的书籍特别有帮助。

答案 5 :(得分:0)

C#委托是封装对象引用和方法指针的对象(检查System.Delegate类)。 它们也可以对object有一个null引用来表示对静态方法的调用。

当使用参数调用委托时,委托使用指定的参数调用引用对象上的引用方法。

已编译的委托Invoke方法由运行时直接处理(使用Reflector可见):

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

运行时使用所有info internaly来编译对引用方法的标准方法调用。