VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Objective-C编程 >
  • c#4.01之Dynamic 1

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

  C# 4.0 引入了 dynamic,让我们可以用类似动态语言的方式对 "未知类型" 对象 "直接" 调用。dynamic 关键字可以在字段、属性、方法参数、方法返回值、委托定义以及本地变量中使用。

class MyClass
{
  public dynamic x;
  public dynamic Y { get; set; }
  public dynamic Test(dynamic o)
  {
    if (o is int)
      return ++o;
    else if (o is string)
      return o + "...";
    else
      return null;
  }
}
class Program
{
  static void Main(string[] args)
  {
    dynamic o = new MyClass();
    o.x = 123;
    o.Y = "hello";
    
    Console.WriteLine(o.Test(o.x));
    Console.WriteLine(o.Test(o.Y));
  }
}

  老规矩,看看编译器到底干了什么。

internal class MyClass
{
  // Fields
  [Dynamic, CompilerGenerated]
  private object <Y>k__BackingField;
  [Dynamic]
  public object x;
  // Methods
  public MyClass();
  
  [return: Dynamic]
  public object Test([Dynamic] object o);
  // Properties
  [Dynamic]
  public object Y { [return: Dynamic] get; [param: Dynamic] set; }
  // Nested Types
  [CompilerGenerated]
  private static class <Test>o__SiteContainer0
  {
    // Fields
    public static CallSite<Func<CallSite, object, object>> <>p__Site1;
    public static CallSite<Func<CallSite, object, string, object>> <>p__Site2;
  }
}

 

  dynamic 被编译器还原成 object,这也能理解。毕竟 C# 基于 CLR 而不是 DLR。对于新出现的 CallSite 比较好奇,就其名字来看应该是对方法调用的 "动态处理"。

  注意: 为了便于阅读,下面的反编译代码中将 "<Main>o__SiteContainer0" 替换成 "SiteContainer0",将 "<>p__Site1" 之类的替换成 "site1"。

[CompilerGenerated]
private static class SiteContainer0
{
  // Fields
  public static CallSite<Func<CallSite, object, int, object>> site1;
  public static CallSite<Func<CallSite, object, string, object>> site2;
  public static CallSite<Action<CallSite, Type, object>> site3;
  public static CallSite<Func<CallSite, object, object, object>> site4;
  public static CallSite<Func<CallSite, object, object>> site5;
  public static CallSite<Action<CallSite, Type, object>> site6;
  public static CallSite<Func<CallSite, object, object, object>> site7;
  public static CallSite<Func<CallSite, object, object>> site8;
}
private static void Main(string[] args)
{
  object o = new MyClass();
  
  if (SiteContainer0.site1 == null)
  {
    SiteContainer0.site1 = CallSite<Func<CallSite, object, int, object>>.Create
    (
      Binder.SetMember
      (
        CSharpBinderFlags.None, 
        "x", 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.LiteralConstant | 
            CSharpArgumentInfoFlags.UseCompileTimeType, null) 
        }
      )
    );
  }
  SiteContainer0.site1.Target(SiteContainer0.site1, o, 0x7b);
  
  if (SiteContainer0.site2 == null)
  {
    SiteContainer0.site2 = CallSite<Func<CallSite, object, string, object>>.Create
    (
      Binder.SetMember
      (
        CSharpBinderFlags.None, 
        "Y", 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.LiteralConstant | 
            CSharpArgumentInfoFlags.UseCompileTimeType, null) 
        }
      )
    );
  }
  
  SiteContainer0.site2.Target(SiteContainer0.site2, o, "hello");
  
  if (SiteContainer0.site3 == null)
  {
    SiteContainer0.site3 = CallSite<Action<CallSite, Type, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.ResultDiscarded, 
        "WriteLine", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | 
            CSharpArgumentInfoFlags.UseCompileTimeType, null),           
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  if (SiteContainer0.site4 == null)
  {
    SiteContainer0.site4 = CallSite<Func<CallSite, object, object, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.None, 
        "Test", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  if (SiteContainer0.site5 == null)
  {
    SiteContainer0.site5 = CallSite<Func<CallSite, object, object>>.Create
    (
      Binder.GetMember
      (
        CSharpBinderFlags.None, 
        "x", 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  SiteContainer0.site3.Target
  (
    SiteContainer0.site3, typeof(Console), 
    SiteContainer0.site4.Target
    (
      SiteContainer0.site4, 
      o, 
      SiteContainer0.site5.Target(SiteContainer0.site5, o)
    )
  );
  
  if (SiteContainer0.site6 == null)
  {
    SiteContainer0.site6 = CallSite<Action<CallSite, Type, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.ResultDiscarded, 
        "WriteLine", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | 
            CSharpArgumentInfoFlags.UseCompileTimeType, null),             
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  if (SiteContainer0.site7 == null)
  {
    SiteContainer0.site7 = CallSite<Func<CallSite, object, object, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.None, 
        "Test", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  if (SiteContainer0.site8 == null)
  {
    SiteContainer0.site8 = CallSite<Func<CallSite, object, object>>.Create
    (
      Binder.GetMember
      (
        CSharpBinderFlags.None, 
        "Y", 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  SiteContainer0.site6.Target
  (
    SiteContainer0.site6, 
    typeof(Console), 
    SiteContainer0.site7.Target
    (
      SiteContainer0.site7, 
      o, 
      SiteContainer0.site8.Target(SiteContainer0.site8, o)
    )
  );
}

 

  事情好像搞大发了,出来这么一大堆,有点晕~~~~。编译器自动创建一个静态类持有一些静态字段,在第一次调用前创建 CallSite<T> 类型的数据,以后都是通过 CallSite<T>.Target 来完成 "动态调用"。可见 CallSite<T> 通过某种途径 "封装" 了动态调用过程。Binder 为这种封装提供了所需的绑定信息。

  为了便于分析,我们用一个简单点的例子来完成对过程的跟踪。

class MyClass
{
  public void Test()
  {
    Console.WriteLine("Hello, World!");
  }
}
class Program
{
  static void Main(string[] args)
  {
    dynamic o = new MyClass();
    o.Test();
  }
}

  反编译代码

[CompilerGenerated]
private static class SiteContainer0
{
  // Fields
  public static CallSite<Action<CallSite, object>> site1;
}
private static void Main(string[] args)
{
  object o = new MyClass();
  
  if (SiteContainer0.site1 == null)
  {
    SiteContainer0.site1 = CallSite<Action<CallSite, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.ResultDiscarded, 
        "Test", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  SiteContainer0.site1.Target(SiteContainer0.site1, o);
}

 

  我们首先看看 Binder.InvokeMemeber() 到底干了什么。

public static class Binder
{
  public static CallSiteBinder InvokeMember(CSharpBinderFlags flags, string name, 
    IEnumerable<Type> typeArguments, Type context, 
    IEnumerable<CSharpArgumentInfo> argumentInfo)
  {
    bool flag = (flags & CSharpBinderFlags.InvokeSimpleName) != CSharpBinderFlags.None;
    bool flag2 = (flags & CSharpBinderFlags.InvokeSpecialName) != CSharpBinderFlags.None;
    bool flag3 = (flags & CSharpBinderFlags.ResultDiscarded) != CSharpBinderFlags.None;
    CSharpCallFlags none = CSharpCallFlags.None;
    if (flag)
    {
      none |= CSharpCallFlags.SimpleNameCall;
    }
    
    if (flag2)
    {
      none |= CSharpCallFlags.EventHookup;
    }
    
    if (flag3)
    {
      none |= CSharpCallFlags.ResultDiscarded;
    }
    
    return new CSharpInvokeMemberBinder(none, name, context, typeArguments, argumentInfo);
  }
}
internal sealed class CSharpInvokeMemberBinder : InvokeMemberBinder, ICSharpInvokeOrInvokeMemberBinder
{
  // Methods
  public CSharpInvokeMemberBinder(CSharpCallFlags flags, string name, Type callingContext, 
    IEnumerable<Type> typeArguments, IEnumerable<CSharpArgumentInfo> argumentInfo);
  public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, 
    DynamicMetaObject errorSuggestion);
  public override DynamicMetaObject FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, 
    DynamicMetaObject errorSuggestion);
  // Properties
  IList<CSharpArgumentInfo> ICSharpInvokeOrInvokeMemberBinder.ArgumentInfo { get; }
  Type ICSharpInvokeOrInvokeMemberBinder.CallingContext { get; }
  CSharpCallFlags ICSharpInvokeOrInvokeMemberBinder.Flags { get; }
  string ICSharpInvokeOrInvokeMemberBinder.Name { get; }
  bool ICSharpInvokeOrInvokeMemberBinder.ResultDiscarded { get; }
  bool ICSharpInvokeOrInvokeMemberBinder.StaticCall { get; }
  IList<Type> ICSharpInvokeOrInvokeMemberBinder.TypeArguments { get; }
}

 

  在 CSharpInvokeMemberBinder 中我们发现了 DynamicMetaObject 这样的字眼,想必和动态调用有所关联。我们暂时不深究,回到最初的流程。

public sealed class CallSite<T> : CallSite where T: class
{
  // Fields
  public T Target;
  // Methods
  public static CallSite<T> Create(CallSiteBinder binder);
  // Properties
  public T Update { get; }
}

  "CallSite<Action<CallSite, object>>.Create(binder),Target 就变成了一个委托字段,也就是说最终的动态调用代码 "SiteContainer0.site1.Target(SiteContainer0.site1, o)" 其实是对这个委托的调用。那么我们可以大胆猜测一下,编译器会使用 binder 提供的信息动态生成一个委托,如此来完成所谓的动态化。

  现在的关注重点就是如何生成委托 Target。

public sealed class CallSite<T> : CallSite where T: class
{
  public static CallSite<T> Create(CallSiteBinder binder)
  {
    return new CallSite<T>(binder);
  }
  private CallSite(CallSiteBinder binder) : base(binder)
  {
    this.Target = this.GetUpdateDelegate();
  }
  private T GetUpdateDelegate()
  {
    return this.GetUpdateDelegate(ref CallSite<T>._CachedUpdate);
  }
  private T GetUpdateDelegate(ref T addr)
  {
    if (((T) addr) == null)
    {
      addr = this.MakeUpdateDelegate();
    }
    return addr;
  }
}

 

  事情落到了 "MakeUpdateDelegate()" 头上。CallSite<T> 内部提供了一个 _CachedUpdate 字段用来缓存以提高性能。

public sealed class CallSite<T> : CallSite where T: class
{
  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);
  }
}
private T CreateCustomNoMatchDelegate(MethodInfo invoke)
{
  ParameterExpression[] parameters = invoke.GetParametersCached()
    .Map<ParameterInfo, ParameterExpression>(p => Expression.Parameter(p.ParameterType, p.Name));
  ParameterExpression expression1 = parameters[0];
  return Expression.Lambda<T>
  (
    Expression.Block
    (
      Expression.Call(typeof(CallSiteOps).GetMethod("SetNotMatched"), parameters
        .First<ParameterExpression>()), 
      Expression.Default(invoke.GetReturnType())
    ), 
    parameters
  ).Compile();
}
private T CreateCustomUpdateDelegate(MethodInfo invoke)
{
  Expression expression9;
  List<Expression> list = new List<Expression>();
  List<ParameterExpression> list2 = new List<ParameterExpression>();
  ... ...
  return Expression.Lambda<T>
  (
    Expression.Label
    (
      target, 
      Expression.Block
      (
        (IEnumerable<ParameterExpression>) new ReadOnlyCollection<ParameterExpression>(list2), 
        (IEnumerable<Expression>) new ReadOnlyCollection<Expression>(list)
      )
    ), 
    "CallSite.Target", 
    true, 
    new ReadOnlyCollection<ParameterExpression>(array)
  ).Compile();
}

 

  不管兜多大的圈子,最终还是回到反射和表达式编译等 "传统" 技术上。不过相比较而言,Deleage.Compile() 后的委托直接调用自然比反射要快些,更何况 dynamic 编译的代码中还增加了 Cache 处理,因此性能应该还可以。

  利用 SOS.dll,我们看看这个生成的动态委托是啥样的。

  !name2ee Learn.CUI.exe Learn.CUI.Program+<Main>o__SiteContainer0

Module: 00a12e8c
Assembly: Learn.CUI.exe
Token: c661cc2302000004
MethodTable: 00a14c00
EEClass: 00a11628
Name: Learn.CUI.Program+<Main>o__SiteContainer0

  !dumpclass 00a11628

Class Name: Learn.CUI.Program+<Main>o__SiteContainer0
mdToken: c661caf302000004
file: d:\system\my documents\visual studio 2010\Projects\...\Learn.CUI.exe
Parent Class: 798e4454
Module: 00a12e8c
Method Table: 00a14c00
Vtable Slots: 4
Total Method Slots: 4
Class Attributes: 100183 Abstract, 
Transparency: Critical
NumInstanceFields: 0
NumStaticFields: 1
 MT Field Offset Type VT Attr Value Name
60fa9280 4000001 4 ...lib]], mscorlib]] 0 static 00cb6b70 <>p__Site1

  !do 00cb6b70

Name: System.Runtime.CompilerServices.CallSite`1[[System.Action`2[[System.Runtime.CompilerServices.CallSite, System.Core],[System.Object, mscorlib]], mscorlib]]
MethodTable: 60fa9280
EEClass: 60e10ff4
Size: 24(0x18) bytes
file: C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll
Fields:
 MT Field Offset Type VT Attr Value Name
60fa8fb0 40006e5 4 ...es.CallSiteBinder 0 instance 00c8baf4 _binder
79be168c 40006e6 8 System.Boolean 1 instance 0 _match
612f0768 40006e4 bc ...ore]], mscorlib]] 0 static c661d13300000000 _SiteCtors
79bdbdd0 40006e7 c System.__Canon 0 instance 00d3caf8 Target
79baab7c 40006e8 10 System.Object[] 0 instance 00d3dbbc Rules
79bdbdd0 40006e9 4 System.__Canon 0 static dynamic statics NYI _CachedUpdate
79bdbdd0 40006ea 8 System.__Canon 0 static dynamic statics NYI _CachedNoMatch
60fae1c0 40006eb c ...on, System.Core]] 0 static dynamic statics NYI CS{$selection}lt;>9__CachedAnonymousMethodDelegate2
60fae1c0 40006ec 10 ...on, System.Core]] 0 static dynamic statics NYI CS{$selection}lt;>9__CachedAnonymousMethodDelegate5
60faeb94 40006ed 14 ...on, System.Core]] 0 static dynamic statics NYI CS{$selection}lt;>9__CachedAnonymousMethodDelegate6

 

  !do 00d3caf8 // Target

Name: System.Action`2[[System.Runtime.CompilerServices.CallSite, System.Core],[System.Object, mscorlib]]
MethodTable: 60fa9208
EEClass: 7990a4fc
Size: 32(0x20) bytes
file: C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
 MT Field Offset Type VT Attr Value Name
79bdbcb8 4000072 4 System.Object 0 instance 00d3a3f4 _target
79bdbcb8 4000073 8 System.Object 0 instance 00d34d10 _methodBase
79bb42b4 4000074 c System.IntPtr 1 instance 034D00B0 _methodPtr
79bb42b4 4000075 10 System.IntPtr 1 instance 00000000 _methodPtrAux
79bdbcb8 4000076 14 System.Object 0 instance bbe3d13300000000 _invocationList
79bb42b4 4000077 18 System.IntPtr 1 instance 00000000 _invocationCount

  !ip2md 034D00B0 // _methodPtr

MethodDesc: 00a16a34
Method Name: DynamicClass.CallSite.Target(System.Runtime.CompilerServices.Closure, System.Runtime.CompilerServices.CallSite, System.Object)
Class: 00a16988
MethodTable: 00a169f4
mdToken: bbe3cccb06000001
Module: 00a16444
IsJitted: yes
CodeAddr: 034d00b0
Transparency: Transparent

  !dumpil 00a16a34

This is dynamic IL. Exception info is not reported at this time.
If a token is unresolved, run "!do <addr>" on the addr given
in parenthesis. You can also look at the token table yourself, by
running "!DumpArray 00d3ca5c".
IL_0000: ldarg.2 
IL_0001: brfalse IL_0020
IL_0006: ldarg.2 
IL_0007: callvirt 6000003 
IL_000c: ldarg.0 
IL_000d: ldfld 4000004 (00d39f54)
IL_0012: ldc.i4.0 
IL_0013: ldelem.ref 
IL_0014: castclass 2000005 
IL_0019: ceq 
IL_001b: br IL_0021
IL_0020: ldc.i4.0 
IL_0021: brfalse IL_0032
IL_0026: ldarg.2 
IL_0027: castclass 2000006 
IL_002c: callvirt 6000007 Learn.CUI.MyClass.Test()
IL_0031: ret 
IL_0032: ldarg.1 
IL_0033: call 6000008 
IL_0038: brfalse IL_003e
IL_003d: ret 
IL_003e: ldarg.1 
IL_003f: castclass 2000009
IL_0044: callvirt 600000a 
IL_0049: ldarg.1 
IL_004a: ldarg.2 
IL_004b: callvirt 600000b 
IL_0050: ret 

 

  反编译的 IL Metadata Token 貌似有点不对劲。(是 SOS.dll 没完工,还是 CLR 4.0 Metadata Token 升级到 64 位了?Beta2, v4.0.21006, SOS.dll v4.0.21006.1)

  虽然 IL 代码有点乱,不过凑活着还是能看个大概的。

  从 MSDN 的介绍上来看,dynamic 是为了和 DLR Object 进行交互,这倒也能理解,毕竟受 C# 静态语言调用规则的限制,我们只能用复杂的 Invoke(name) 模式,很显然不利于提升开发效率和简化代码维护。不过 dynamic 同样也带来重构等方面的问题,这也需关注。个人觉得如果没有必要的话,还是尽量少用吧。对于那些需要做反射调用的地方,可以考虑一下,但也尽可能局限于某个 Inner Block,dynamic object 最好也局限于某个有限的 Context 之中。

  dynamic 一个非常有用的作用就是 UnitTest,如此我们可以事先写好调用逻辑,即便我们从没实现它,也一样可以编译。

 

 

  dynamic 被编译器还原成 object,这也能理解。毕竟 C# 基于 CLR 而不是 DLR。对于新出现的 CallSite 比较好奇,就其名字来看应该是对方法调用的 "动态处理"。

  注意: 为了便于阅读,下面的反编译代码中将 "<Main>o__SiteContainer0" 替换成 "SiteContainer0",将 "<>p__Site1" 之类的替换成 "site1"。

[CompilerGenerated]
private static class SiteContainer0
{
  // Fields
  public static CallSite<Func<CallSite, object, int, object>> site1;
  public static CallSite<Func<CallSite, object, string, object>> site2;
  public static CallSite<Action<CallSite, Type, object>> site3;
  public static CallSite<Func<CallSite, object, object, object>> site4;
  public static CallSite<Func<CallSite, object, object>> site5;
  public static CallSite<Action<CallSite, Type, object>> site6;
  public static CallSite<Func<CallSite, object, object, object>> site7;
  public static CallSite<Func<CallSite, object, object>> site8;
}
private static void Main(string[] args)
{
  object o = new MyClass();
  
  if (SiteContainer0.site1 == null)
  {
    SiteContainer0.site1 = CallSite<Func<CallSite, object, int, object>>.Create
    (
      Binder.SetMember
      (
        CSharpBinderFlags.None, 
        "x", 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.LiteralConstant | 
            CSharpArgumentInfoFlags.UseCompileTimeType, null) 
        }
      )
    );
  }
  SiteContainer0.site1.Target(SiteContainer0.site1, o, 0x7b);
  
  if (SiteContainer0.site2 == null)
  {
    SiteContainer0.site2 = CallSite<Func<CallSite, object, string, object>>.Create
    (
      Binder.SetMember
      (
        CSharpBinderFlags.None, 
        "Y", 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.LiteralConstant | 
            CSharpArgumentInfoFlags.UseCompileTimeType, null) 
        }
      )
    );
  }
  
  SiteContainer0.site2.Target(SiteContainer0.site2, o, "hello");
  
  if (SiteContainer0.site3 == null)
  {
    SiteContainer0.site3 = CallSite<Action<CallSite, Type, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.ResultDiscarded, 
        "WriteLine", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | 
            CSharpArgumentInfoFlags.UseCompileTimeType, null),           
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  if (SiteContainer0.site4 == null)
  {
    SiteContainer0.site4 = CallSite<Func<CallSite, object, object, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.None, 
        "Test", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  if (SiteContainer0.site5 == null)
  {
    SiteContainer0.site5 = CallSite<Func<CallSite, object, object>>.Create
    (
      Binder.GetMember
      (
        CSharpBinderFlags.None, 
        "x", 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  SiteContainer0.site3.Target
  (
    SiteContainer0.site3, typeof(Console), 
    SiteContainer0.site4.Target
    (
      SiteContainer0.site4, 
      o, 
      SiteContainer0.site5.Target(SiteContainer0.site5, o)
    )
  );
  
  if (SiteContainer0.site6 == null)
  {
    SiteContainer0.site6 = CallSite<Action<CallSite, Type, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.ResultDiscarded, 
        "WriteLine", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.IsStaticType | 
            CSharpArgumentInfoFlags.UseCompileTimeType, null),             
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  if (SiteContainer0.site7 == null)
  {
    SiteContainer0.site7 = CallSite<Func<CallSite, object, object, object>>.Create
    (
      Binder.InvokeMember
      (
        CSharpBinderFlags.None, 
        "Test", 
        null, 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  if (SiteContainer0.site8 == null)
  {
    SiteContainer0.site8 = CallSite<Func<CallSite, object, object>>.Create
    (
      Binder.GetMember
      (
        CSharpBinderFlags.None, 
        "Y", 
        typeof(Program), 
        new CSharpArgumentInfo[] 
        { 
          CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) 
        }
      )
    );
  }
  
  SiteContainer0.site6.Target
  (
    SiteContainer0.site6, 
    typeof(Console), 
    SiteContainer0.site7.Target
    (
      SiteContainer0.site7, 
      o, 
      SiteContainer0.site8.Target(SiteContainer0.site8, o)
    )
  );
}


相关教程