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

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

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

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

有关一个简单的示例(访问类型的静态T Parse(string)模式),请参见下文。 请注意,它只使用一次reflection(每种类型),而不是很多次。 这应该超出reflection或典型的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.Parse("123"); float f = Test.Parse("123.45"); } } static class Test { public static T Parse(string text) { return parse(text); } static readonly Func parse; static Test() { try { MethodInfo method = typeof(T).GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(string) }, null); parse = (Func) Delegate.CreateDelegate( typeof(Func), method); } catch (Exception ex) { string msg = ex.Message; parse = delegate { throw new NotSupportedException(msg); }; } } } 

定义委托时

 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来自C# ,第17章

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

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

这两条信息可识别任何方法。

如何有效地使用它们?

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

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

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

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

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

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

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

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