2009-02-09 71 views
7

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

回答

4

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

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

这两条信息标识任何方法。

它们如何有效使用?

你是什么意思?你知道事件还是你的问题更专业?

+0

真的吗?他们存储指针?我的印象是事件的确如此,而且代表们有点像强类型的函数类型。 (但我可能会把事情弄混淆。) – scraimer 2009-02-09 09:17:41

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

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

1

当你创建一个委托时,C#编译器会生成一个完整的类。 这个类包含了一个函数引用列表,正如Konrad所说的。 关于委托的好处是它们为您提供了简单的方法,以通知回调异步执行任务。这意味着您可以在后台操作完成时收到通知。 线程池不提供此功能。 代表是一个广泛的话题,我发现杰夫里希特(通过C#的CLR)和Albahari(C#3)书籍提供了特别的帮助。

0

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

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

编译的委托Invoke方法是直接由运行时处理(如用反射可见):

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

运行时使用所有信息internaly编译一个标准方法调用来引用方法。

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章