C# “如何在CIL(MSIL)中使用”;调用实例void valuetype[…type]”;返回值还是保存值?(通用中间语言)

C# “如何在CIL(MSIL)中使用”;调用实例void valuetype[…type]”;返回值还是保存值?(通用中间语言),c#,cil,mono.cecil,C#,Cil,Mono.cecil,我正在创建一个.Net中间代码模拟器,它一条接一条地执行CIL指令。 我很难更精确地模拟调用实例void valuetype并保存其结果 我有C代码:DateTime?startDate=日期时间。现在 这是为了: IL_010d: ldloca.s startDate IL_010f: call valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now() IL_0114: call

我正在创建一个.Net中间代码模拟器,它一条接一条地执行CIL指令。 我很难更精确地模拟
调用实例void valuetype
并保存其结果

我有C代码:
DateTime?startDate=日期时间。现在

这是为了:

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_010d: call         valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Now()
IL_0112: stloc.2      // startDate
  • IL_010d
    -
    call
    上将值推送到堆栈上
  • IL_0112
    -
    stloc
    上,从堆栈中弹出值并保存在局部变量中
在这种情况下,一切对我来说都很清楚。i、 e.执行块后,堆栈上没有对象,并且
DateTime。现在
已写入局部变量
startDate

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

的主要区别在于,通过向变量声明中添加符号,可以将其类型设置为,而不是简单地
System.DateTime
。以下两种声明基本上是等效的:

DateTime? d1 = DateTime.Now;
System.Nullable<DateTime> d1 = DateTime.Now;
DateTime?d1=日期时间。现在;
System.Nullable d1=DateTime.Now;
因此:

IL_010d将局部变量(
startDate
)的地址推送到堆栈中

IL_010f
DateTime的结果推送到堆栈中

IL_0114调用
null
构造函数(使用
startDate
的地址作为)传递
DateTime的结果。现在
(它初始化
startDate


Adriano

主要区别在于,通过在变量声明中添加符号,可以将其类型设置为,而不是简单的
System.DateTime
。以下两种声明基本上是等效的:

DateTime? d1 = DateTime.Now;
System.Nullable<DateTime> d1 = DateTime.Now;
DateTime?d1=日期时间。现在;
System.Nullable d1=DateTime.Now;
因此:

IL_010d将局部变量(
startDate
)的地址推送到堆栈中

IL_010f
DateTime的结果推送到堆栈中

IL_0114调用
null
构造函数(使用
startDate
的地址作为)传递
DateTime的结果。现在
(它初始化
startDate

Adriano

没有“
调用实例void valuetype
”。只有
调用
,其余为方法引用

对于更简单的代码,
valuetype[mscorlib]System.DateTime[mscorlib]System.DateTime::get_Now()
是方法引用,但
valuetype[mscorlib]System.DateTime
只是返回类型的一部分(具有
valuetype
以指示该类型的未装箱形式,与
装箱
相反)

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

此处调用的方法是
实例void valuetype[mscorlib]System.Nullable`1::.ctor(!0)
,即构造函数。每个构造函数实际上都返回
void
,因此,如果没有任何特殊指令,堆栈在调用后是空的,并且由于方法也是
实例
,因此它需要
引用。这里的
值类型
再次表明您正在对未固定值的e型

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

没有“
调用实例void valuetype
”。只有
调用
,其余为方法引用

对于更简单的代码,
valuetype[mscorlib]System.DateTime[mscorlib]System.DateTime::get_Now()
是方法引用,但
valuetype[mscorlib]System.DateTime
只是返回类型的一部分(具有
valuetype
以指示该类型的未装箱形式,与
装箱
相反)

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

此处调用的方法是
实例void valuetype[mscorlib]System.Nullable`1::.ctor(!0)
,即构造函数。每个构造函数实际上都返回
void
,因此,如果没有任何特殊指令,堆栈在调用后是空的,并且由于方法也是
实例
,因此它需要
引用。这里的
值类型
再次表明您正在对未固定值的e型


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

在IL_0114中也是如此-我从堆栈中得到两个数据-第一个是这个,它是由IL_010d中的值“启动”的(不需要newobj)。第二个是现在有值的datetime。调用值变量的构造函数会更改变量本身的值?不需要newobj):正是。在这种情况下,值类型