代表们如何在幕后工作?如何有效地使用它们?
编辑:我知道它们是如何在表面上工作的(它们基本上是函数指针,并允许使用其地址调用某些签名的回调方法)。我需要知道的是CLR如何在内部实际实现它们。在定义委托时以及使用委托对象调用回调方法时,幕后究竟发生了什么?答案 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.Combine
和Delegate.Remove
)等于添加到该列表和从该列表中删除。
有关更多低级别信息,请参阅ECMA-335(CLI标准),第II.14.5节(方法指针)和II.14.6(代表)。特别要注意,委托包含一个实例指针(类型为System.Object
)和一个方法指针(类型为System.IntPtr
)。可以通过ldftn
或ldvirtftn
(用于虚函数调用)指令获取方法指针(在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来编译对引用方法的标准方法调用。