.NET 4.0:一段动态绑定代码的底层初级分析

  随着本月12号VS2010的正式发布,相信越来越多的人都会把开发工具升级到VS2010。同时,相信很多人都会用到C# 4.0提供的新功能-动态绑定。我们知道,动态绑定在.NET Framework 4.0里通过一个叫做DLR的来执行的。那么它是怎样实现的呢?请看下面一段代码:

 public dynamic Foo(dynamic x, dynamic y)
 { 
      
return x / y;
 }

  这个方法代表可以处理所有数值类型的dynamic版本。首先,我们把这个方法编译,然后通过Reflector(版本号:6.1.0.11)查看这个方法的反编译结果,我们会看到如下这样的一个方法:

代码
 [return: Dynamic]
 
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, 
          
objectobjectobject>>.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的原型如下:

[CompilerGenerated]
private static class <Foo>o__SiteContainer2
{

    public static CallSite<Func<CallSite, objectobjectobject>> <>p__Site3;
}

原来,编译器生成了一个静态类。再往后看,我们会发现另一个特殊的类:CallSite<T>。在Reflector的帮助下,我们顺利的在System.Runtime.CompilerServices命名空间下找到了它, 我们会看到CallSite<T>类继承自CallSite类。然后,我们找到CallSite<T>类的静态Create方法,代码如下:

public static CallSite<T> Create(CallSiteBinder binder)
{
    
return new CallSite<T>(binder);
}

然后,我们找到CallSite<T>类的对应构造方法的源代码:

private CallSite(CallSiteBinder binder) : base(binder)
{
    
this.Target = this.GetUpdateDelegate();
}

然后,我们找到GetUpdateDelegate方法的源代码

private T GetUpdateDelegate()
{
    
return this.GetUpdateDelegate(ref CallSite<T>._CachedUpdate);
}

再找到GetUpdateDelegate方法的另一个重载版本,如下:

private T GetUpdateDelegate(ref T addr)
{
    
if (((T) addr) == null)
    {
        addr 
= this.MakeUpdateDelegate();
    }
    
return addr;
}

于是,我们再找到MakeUpdateDelegate方法,代码如下:

代码
internal T 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的帮助下,我们初步理解了动态绑定的执行过程,对于程序员来讲,这非常重要。

 

 

 

 

posted @ 2010-04-25 17:36  残香恨  阅读(1092)  评论(0编辑  收藏  举报