如何在CIL (MSIL) "call instance void valuetype [..type]" return 或中保存值? (通用中间语言)

How in CIL (MSIL) "call instance void valuetype [..type]" return or save value? (Common Intermediate Language)

我正在创建一个 .Net 中间代码模拟器,它在指令后执行 CIL 指令。 我在保存结果

时无法更准确地模拟 call instance void valuetype

我有 C# 代码:DateTime? startDate = DateTime.Now;

编译为:

IL_010d: ldloca.s     startDate
IL_010f: call         valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
IL_0114: call         instance void valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>::.ctor(!0/*valuetype [mscorlib]System.DateTime*/)

我的第一个问题是:IL_0114 发生了什么?调用方法执行后栈应该是什么样子的? DateTime.Now 值将如何输入到本地 startData 变量以及在什么时候输入?

替代方案,如果我将 C# 代码更改为 DateTime startDate = DateTime.Now;(没有?) 编译为:

IL_010d: call         valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
IL_0112: stloc.2      // startDate

这样的话,我就明白了。即执行块后,堆栈上没有对象并且DateTime.Now已被写入局部变量startDate

我的第二个问题是这两个调用有什么区别? call instance void valuetype(IL_0114) 与 call valuetype(IL_010d)

主要区别在于,通过将符号 ? 添加到变量声明中,您将其类型设置为 Nullable<T>而不是简单地 System.DateTime。基本上下面的两个声明是等价的:

DateTime? d1 = DateTime.Now;
System.Nullable<DateTime> d1 = DateTime.Now;

所以:

IL_010d将局部变量(startDate)的地址压入栈

IL_010fDateTime.Now的结果压入栈

IL_0114调用Nullable<DateTime>构造函数(使用startDate的地址作为this)传递 DateTime.Now 的结果(初始化 startDate

阿德里亚诺

没有“call instance void valuetype”。只有call,其余为方法参考

在更简单的代码中,valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now() 是方法引用,但 valuetype [mscorlib]System.DateTime 只是 return 类型的一部分(有 valuetype 表示类型的未装箱形式,与 boxedclass).

相反

调用 get_Now 后,值进入堆栈。但是,当您将它转换为 Nullable<DateTime> 类型的变量时,您实际上调用了它的构造函数,该构造函数负责正确初始化值。

这里调用的方法是instance void valuetype [mscorlib]System.Nullable`1<valuetype [mscorlib]System.DateTime>::.ctor(!0),即构造函数。每个构造函数实际上returns void,所以没有任何特殊说明,调用后堆栈为空,并且由于该方法也是instance,因此需要一个this引用.同样 valuetype 这里表示您正在对该类型的未装箱值调用该方法。

这是在已分配存储位置时初始化值类型的常用方法之一。您只需获取其地址并调用构造函数 in-place,而不是使用 newobj。同样,initobj指令zero-initializes它,就好像调用了默认构造函数一样。