Jam*_*man 6 c# compiler-construction reflection il dynamic
我一直在使用LINQPad中的一些C#语句来理解发出的中间语言代码.
我首先尝试了以下代码:
var Container = new {Name = "James"};
Console.WriteLine(Container.Name);
Run Code Online (Sandbox Code Playgroud)
并且看到以下六行IL发射:
IL_0001: ldstr "James"
IL_0006: newobj <>f__AnonymousType0<System.String>..ctor
IL_000B: stloc.0
IL_000C: ldloc.0
IL_000D: callvirt <>f__AnonymousType0<System.String>.get_Name
IL_0012: call System.Console.WriteLine
Run Code Online (Sandbox Code Playgroud)
这是我所期望的,并且非常好地演示了匿名类型是如何只读/不可变的,因为没有set_Name属性.
接下来我尝试了这些陈述:
dynamic Container = new System.Dynamic.ExpandoObject();
Container.Name = "James";
Console.WriteLine(Container.Name);
Run Code Online (Sandbox Code Playgroud)
这会导致大量的IL被释放.我不会在这里粘贴它,但你可以在这个pastebin中找到它.
我理解在管理动态类型和ExpandoObject方面存在相当多的开销,但我不明白为什么看起来System.Console.WriteLine在这种情况下调用是通过内部反射来执行的.
IL_0072: ldstr "WriteLine"
....
IL_00BF: ldtoken System.Console
Run Code Online (Sandbox Code Playgroud)
在第一段代码中,在检索并存储属性之后,它是一个调用的单行IL语句System.Console.WriteLine.
那么为什么一个dynamic类型的呼叫需要额外的所有这些?
因为变量是dynamic在编译时无法知道WriteLine应该调用哪个重载.直到运行时我们才知道dynamic对象的实际类型.由于方式dynamic有效,重要的是它不仅仅被视为object编译时; 部分权力是它在运行时确定正确的过载.
如果你将对象转换为动态以外的东西(即string在调用之后ToString或者只是回到ExpandoObject它WriteLine之后),然后将其传递给那么你应该看到反射调用消失了,并且在编译时看到它静态地确定了正确的重载WriteLine.