如何在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*/)
- on
IL_010d
- ldloca
将堆栈引用推送到局部变量 startDate
- on
IL_010f
- call
压入堆栈值类型 DateTime==Now
我的第一个问题是: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
- on
IL_010d
- call
将值压入堆栈
- on
IL_0112
- stloc
从堆栈中弹出值并保存在局部变量中
这样的话,我就明白了。即执行块后,堆栈上没有对象并且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_010f将DateTime.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
表示类型的未装箱形式,与 boxed
或 class
).
相反
调用 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它,就好像调用了默认构造函数一样。
我正在创建一个 .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*/)
- on
IL_010d
-ldloca
将堆栈引用推送到局部变量startDate
- on
IL_010f
-call
压入堆栈值类型 DateTime==Now
我的第一个问题是: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
- on
IL_010d
-call
将值压入堆栈 - on
IL_0112
-stloc
从堆栈中弹出值并保存在局部变量中
这样的话,我就明白了。即执行块后,堆栈上没有对象并且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_010f将DateTime.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
表示类型的未装箱形式,与 boxed
或 class
).
调用 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它,就好像调用了默认构造函数一样。