.NET 4.0:一段动态绑定代码的底层初级分析
随着本月12号VS2010的正式发布,相信越来越多的人都会把开发工具升级到VS2010。同时,相信很多人都会用到C# 4.0提供的新功能-动态绑定。我们知道,动态绑定在.NET Framework 4.0里通过一个叫做DLR的来执行的。那么它是怎样实现的呢?请看下面一段代码:
{
return x / y;
}
这个方法代表可以处理所有数值类型的dynamic版本。首先,我们把这个方法编译,然后通过Reflector(版本号:6.1.0.11)查看这个方法的反编译结果,我们会看到如下这样的一个方法:
private static object Foo([Dynamic] object x, [Dynamic] object y)
{
if (<Foo>o__SiteContainer2.<>p__Site3 == null)
{
<Foo>o__SiteContainer2.<>p__Site3 = CallSite<Func<CallSite,
object, object, object>>.Create(Binder.BinaryOperation(
CSharpBinderFlags.None, ExpressionType.Divide,
typeof(Program), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
}));
}
return <Foo>o__SiteContainer2.<>p__Site3.Target(
<Foo>o__SiteContainer2.<>p__Site3, x, y);
}
其中,Program是当前Foo方法所在类的类名。我们会发现,<Foo>o__SiteContainer2这段特殊的代码,通过Reflector的帮助,我们会看到<Foo>o__SiteContainer2的原型如下:
private static class <Foo>o__SiteContainer2
{
public static CallSite<Func<CallSite, object, object, object>> <>p__Site3;
}
原来,编译器生成了一个静态类。再往后看,我们会发现另一个特殊的类:CallSite<T>。在Reflector的帮助下,我们顺利的在System.Runtime.CompilerServices命名空间下找到了它, 我们会看到CallSite<T>类继承自CallSite类。然后,我们找到CallSite<T>类的静态Create方法,代码如下:
{
return new CallSite<T>(binder);
}
然后,我们找到CallSite<T>类的对应构造方法的源代码:
{
this.Target = this.GetUpdateDelegate();
}
然后,我们找到GetUpdateDelegate方法的源代码
{
return this.GetUpdateDelegate(ref CallSite<T>._CachedUpdate);
}
再找到GetUpdateDelegate方法的另一个重载版本,如下:
{
if (((T) addr) == null)
{
addr = this.MakeUpdateDelegate();
}
return addr;
}
于是,我们再找到MakeUpdateDelegate方法,代码如下:
{
Type[] typeArray;
Type delegateType = typeof(T);
MethodInfo method = delegateType.GetMethod("Invoke");
if (delegateType.IsGenericType && CallSite<T>.IsSimpleSignature(method, out typeArray))
{
MethodInfo info2 = null;
MethodInfo info3 = null;
if (method.ReturnType == typeof(void))
{
if (delegateType == DelegateHelpers.GetActionType(typeArray.AddFirst<Type>(typeof(CallSite))))
{
info2 = typeof(UpdateDelegates).GetMethod("UpdateAndExecuteVoid" + typeArray.Length, BindingFlags.NonPublic | BindingFlags.Static);
info3 = typeof(UpdateDelegates).GetMethod("NoMatchVoid" + typeArray.Length, BindingFlags.NonPublic | BindingFlags.Static);
}
}
else if (delegateType == DelegateHelpers.GetFuncType(typeArray.AddFirst<Type>(typeof(CallSite))))
{
info2 = typeof(UpdateDelegates).GetMethod("UpdateAndExecute" + (typeArray.Length - 1), BindingFlags.NonPublic | BindingFlags.Static);
info3 = typeof(UpdateDelegates).GetMethod("NoMatch" + (typeArray.Length - 1), BindingFlags.NonPublic | BindingFlags.Static);
}
if (info2 != null)
{
CallSite<T>._CachedNoMatch = (T) info3.MakeGenericMethod(typeArray).CreateDelegate(delegateType);
return (T) info2.MakeGenericMethod(typeArray).CreateDelegate(delegateType);
}
}
CallSite<T>._CachedNoMatch = this.CreateCustomNoMatchDelegate(method);
return this.CreateCustomUpdateDelegate(method);
}
一切都明白了。原来,.NET通过一个中间静态类来保存CallSite<T>,只有在第一次执行时,才执行以上这些消耗性能的步骤,第二次执行时,速度会快得多。
最后,在Reflector的帮助下,我们初步理解了动态绑定的执行过程,对于程序员来讲,这非常重要。