C# IL中调用实例与newobj实例之间的差异
我正在深入研究C#,并使用可空值类型。出于实验目的,我写了一段代码:C# IL中调用实例与newobj实例之间的差异,c#,il,C#,Il,我正在深入研究C#,并使用可空值类型。出于实验目的,我写了一段代码: private static void HowNullableWorks() { int test = 3; int? implicitConversion = test; Nullable<int> test2 = new Nullable<int>(3); MethodThatTakesNullableInt(null
private static void HowNullableWorks()
{
int test = 3;
int? implicitConversion = test;
Nullable<int> test2 = new Nullable<int>(3);
MethodThatTakesNullableInt(null);
MethodThatTakesNullableInt(39);
}
private static void HowNullableWorks()
{
int检验=3;
int?隐式转换=测试;
Nullable test2=新的Nullable(3);
方法获取空值(null);
方法:采用随机分组法(39例);
}
我很高兴看到implicitConversion/test2变量初始化为:
call instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
调用实例void valuetype[mscorlib]System.Nullable`1::.ctor(!0)
指令,而当调用采用LLABLEINT的方法时,我可以看到:
IL_0017: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0017:initobj值类型[mscorlib]系统。可为null`1
及
IL_0026:newobj实例void valuetype[mscorlib]System.Nullable`1::.ctor(!0)
我明白。我想我也会看到隐式转换的newobj指令
这是完整的IL代码:
.method private hidebysig static void HowNullableWorks() cil managed
{
// Code size 50 (0x32)
.maxstack 2
.locals init ([0] int32 test,
[1] valuetype [mscorlib]System.Nullable`1<int32> implicitConversion,
[2] valuetype [mscorlib]System.Nullable`1<int32> test2,
[3] valuetype [mscorlib]System.Nullable`1<int32> CS$0$0000)
IL_0000: nop
IL_0001: ldc.i4.3
IL_0002: stloc.0
IL_0003: ldloca.s implicitConversion
IL_0005: ldloc.0
IL_0006: call instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_000b: nop
IL_000c: ldloca.s test2
IL_000e: ldc.i4.3
IL_000f: call instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0014: nop
IL_0015: ldloca.s CS$0$0000
IL_0017: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_001d: ldloc.3
IL_001e: call void csharp.in.depth._2nd.Program::MethodThatTakesNullableInt(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0023: nop
IL_0024: ldc.i4.s 39
IL_0026: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_002b: call void csharp.in.depth._2nd.Program::MethodThatTakesNullableInt(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0030: nop
IL_0031: ret
} // end of method Program::HowNullableWorks
.method private hidebysing static void HowNullableWorks()cil managed
{
//代码大小50(0x32)
.maxstack 2
.init([0]int32测试,
[1] valuetype[mscorlib]系统。可为null的`1隐式转换,
[2] valuetype[mscorlib]系统。可为null的'1 test2,
[3] valuetype[mscorlib]系统。可为空'1 CS$0$0000)
IL_0000:没有
IL_0001:ldc.i4.3
IL_0002:stloc.0
IL_0003:ldloca.s隐式转换
IL_0005:ldloc.0
IL_0006:调用实例void valuetype[mscorlib]System.Nullable`1::.ctor(!0)
没有
IL_000c:ldloca.s测试2
IL_000e:ldc.i4.3
IL_000f:调用实例void valuetype[mscorlib]System.Nullable`1::.ctor(!0)
IL_0014:没有
IL_0015:ldloca.s CS$0$0000
IL_0017:initobj valuetype[mscorlib]系统。可为null`1
IL_001d:ldloc.3
IL_001e:调用void csharp.in.depth._2nd.Program::MethodThatTakesNullableInt(valuetype[mscorlib]System.Nullable`1)
伊卢0023:没有
IL_0024:ldc.i4.s 39
IL_0026:newobj实例void valuetype[mscorlib]System.Nullable`1::.ctor(!0)
IL_002b:调用void csharp.in.depth._2nd.Program::MethodThatTakesNullableInt(valuetype[mscorlib]System.Nullable`1)
IL_0030:没有
IL_0031:ret
}//方法结束程序::HowNullableWorks
首先,它看起来像是在调试模式下编译的(基于nop
s)-如果在发布模式下编译,可能会看到不同的代码发出
ECMA CLR规范(初始化值类型实例)第I.12.1.6.2.1节规定:
初始化值类型的主目录有三个选项
例如。您可以通过加载家庭地址将其归零(请参见
表I.8:原籍地址和类型)和使用initobj
指令(对于局部变量,也可通过设置
方法头中的localsinit
位)。你可以打个电话
通过加载家庭地址的用户定义构造函数(参见表
I.8:家庭地址和类型),然后致电
直接调用构造函数。或者,您可以将现有实例复制到
家庭,如§I.12.1.6.2.2所述
代码中可空类型的前三次使用导致以局部变量存储空值,因此此注释是相关的(局部变量是值的一种类型):前两次是您声明的局部变量implicitConversion
和test
,第三个是编译器生成的名为CS$0$0000
的临时文件。正如ECMA规范所指出的,可以通过使用initobj
(相当于结构的默认无参数构造函数,在这种情况下用于CS$0$0000
)或通过加载本地地址并调用构造函数(用于其他两个本地值)来初始化这些本地值
但是,对于最后一个可为null的实例(由39
的隐式转换创建),结果不会存储在本地文件中,而是在堆栈上生成的,因此初始化主文件的规则在此不适用。相反,编译器只使用newobj
在堆栈上创建值(与任何值或引用类型一样)
您可能想知道为什么编译器为调用MethodThatTakesNullableInt(null)
而不是为调用MethodThatTakesNullableInt(39)
生成一个本地函数。我怀疑答案是编译器总是使用initobj
调用默认构造函数(然后需要值的本地或其他home),但在还没有合适的home时,使用newobj
调用其他构造函数并将结果存储在堆栈上
有关更多信息,请参见规范第III.4.21节(新OBJ)中的注释:
通常不会使用newobj
创建值类型。他们通常是
使用newarr
(用于
零基一维数组),或作为对象的字段。一旦
分配后,使用initobj
初始化它们。但是,newobj
指令可用于在上创建值类型的新实例
然后可以作为参数传递的堆栈,存储在本地,
等等
.method private hidebysig static void HowNullableWorks() cil managed
{
// Code size 50 (0x32)
.maxstack 2
.locals init ([0] int32 test,
[1] valuetype [mscorlib]System.Nullable`1<int32> implicitConversion,
[2] valuetype [mscorlib]System.Nullable`1<int32> test2,
[3] valuetype [mscorlib]System.Nullable`1<int32> CS$0$0000)
IL_0000: nop
IL_0001: ldc.i4.3
IL_0002: stloc.0
IL_0003: ldloca.s implicitConversion
IL_0005: ldloc.0
IL_0006: call instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_000b: nop
IL_000c: ldloca.s test2
IL_000e: ldc.i4.3
IL_000f: call instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_0014: nop
IL_0015: ldloca.s CS$0$0000
IL_0017: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_001d: ldloc.3
IL_001e: call void csharp.in.depth._2nd.Program::MethodThatTakesNullableInt(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0023: nop
IL_0024: ldc.i4.s 39
IL_0026: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_002b: call void csharp.in.depth._2nd.Program::MethodThatTakesNullableInt(valuetype [mscorlib]System.Nullable`1<int32>)
IL_0030: nop
IL_0031: ret
} // end of method Program::HowNullableWorks