第一个版本总是比较慢。用这个版本非常简单的术语来说,编译器在编译时可以做的所有事情现在都必须在运行时完成,即。检查 a 和 b 的类型,查找它们是否支持 + 运算符等等。它会缓存很多这样的东西,但它仍然比调用委托要多得多。
在第二个版本中,所有这些检查都可以在编译期间完成。运行时的成本只是委托的创建和调用。
例如,考虑这些方法:
static T Add<T>(T a, T b)
{
return ((dynamic)a) + ((dynamic)b);
}
对比
static T Add<T>(T a, T b, Func<T, T, T> adder)
{
return adder(a, b);
}
这是编译器从第一个方法生成的:
private static T Add<T>(T a, T b)
{
if (Program.<Add>o__SiteContainer0<T>.<>p__Site1 == null)
{
Program.<Add>o__SiteContainer0<T>.<>p__Site1 = CallSite<Func<CallSite, object, T>>.Create(Binder.Convert(CSharpBinderFlags.None, typeof(T), typeof(Program)));
}
Func<CallSite, object, T> arg_98_0 = Program.<Add>o__SiteContainer0<T>.<>p__Site1.Target;
CallSite arg_98_1 = Program.<Add>o__SiteContainer0<T>.<>p__Site1;
if (Program.<Add>o__SiteContainer0<T>.<>p__Site2 == null)
{
Program.<Add>o__SiteContainer0<T>.<>p__Site2 = CallSite<Func<CallSite, object, object, object>>.Create(Binder.BinaryOperation(CSharpBinderFlags.None, ExpressionType.Add, typeof(Program), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
return arg_98_0(arg_98_1, Program.<Add>o__SiteContainer0<T>.<>p__Site2.Target(Program.<Add>o__SiteContainer0<T>.<>p__Site2, a, b));
}
我做了一些粗略的测量,在我的机器上,第一个版本比第二个版本慢了大约 5 倍。我不得不承认,我本来预计差异会更大。
更新:至于证明为什么这比委托慢:鉴于生成的调用站点代码还涉及委托的调用(arg_98_0),这段代码(委托+ X的调用)必须比只使用委托要慢。