首页 > 编程开发 > Objective-C编程 >
-
c#4.01之Dynamic 1
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)
)
);
}