C# 动态类型导致 Console.WriteLine 在 IL 中通过反射解析

标签 c# dynamic reflection compiler-construction il

我一直在研究 LINQPad 中的一些 C# 语句以了解发出了什么中间语言代码。

我首先尝试了以下代码:

var Container = new {Name = "James"};
Console.WriteLine(Container.Name);

然后看到发出了以下六行 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

这大致符合我的预期,并且很好地展示了匿名类型是如何只读/不可变的,因为没有 set_Name 属性。

接下来我尝试了语句:

dynamic Container = new System.Dynamic.ExpandoObject();
Container.Name = "James";
Console.WriteLine(Container.Name);

这导致大量 IL 被释放。我不会在这里粘贴,但您可以在 this pastebin 中找到它.

我知道在管理动态类型和 ExpandoObject 方面有相当多的开销,但我不明白为什么对 System.Console.WriteLine 的调用似乎在这里通过内部反射(reflection)进行的案例。

IL_0072:  ldstr       "WriteLine"
....
IL_00BF:  ldtoken     System.Console

在第一段代码中,在检索并存储属性之后,它是一条调用 System.Console.WriteLine 的单行 IL 语句。

那么为什么使用 dynamic 类型的调用需要所有这些额外的东西?

最佳答案

因为变量是动态,所以在编译时无法知道应该调用WriteLine 的哪个重载。直到运行时我们才知道 dynamic 对象的实际类型。由于 dynamic 的工作方式,重要的是它不仅在编译时被视为一个 object;部分功能在于它在运行时确定正确的过载。

如果您将对象转换为非动态对象(即调用 ToString 后的 string 或返回 ExpandoObject)然后将其传递到 WriteLine 然后你应该看到反射调用消失并看到它在编译时静态地确定 WriteLine 的正确重载。

关于C# 动态类型导致 Console.WriteLine 在 IL 中通过反射解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12519738/

相关文章:

c# - 使用 Internet Explorer 的 asp.net 登录控件

c# - 我可以在现有方法中发出 CIL 吗?

asp.net - 动态向 'GridView' 添加超链接列(服务器端)

java - 如何通过反射获取类的 Array 字段?

C# 获取 CSS 背景图像的完整 URL 链接

c# - 通过反射实例化一组不可访问的类

c# - 在 Teams 机器人中发送打字事件失败 - BadGateway

postgresql - postgresql 中的动态更新

c# - 设置动态创建的枚举值的赋值表达式

C# 在派生类上隐藏方法并使用属性