为什么值类型字段可以实例化,而不是初始化?

时间:2017-10-25 16:02:25

标签: .net clr cil

如果S s;使用{struct S{}声明构造函数,则通过调用其构造函数(例如a = new S(11))初始化值类型局部变量(例如S给定int) {1}}参数。然后new S(11)编译为:

ldloca.s   V_0
ldc.i4.s   11
call       instance void S::.ctor(int32)

但是当s是一个字段(例如class C { S s;)时,它不会以相同的方式初始化。关于类C的以下实例方法:void setS(int n) { s = new S(n); }它将编译为:

ldarg.0
ldarg.1
newobj     instance void S::.ctor(int32)
stfld      valuetype S C::s

我原以为它会编译成以下代码,这更接近局部变量的情况:

ldarg.0
ldflda    valuetype S C::s
ldarg.1
call       instance void S::.ctor(int32)

此外,如果我清楚地理解,newobj instance void S::.ctor(int32)有更高的开销并且负担GC。我是对的吗?

为什么,C#编译器使用值类型字段的方法与用于局部变量的方法不同?

1 个答案:

答案 0 :(得分:4)

基本上,为了将构造函数调用与赋值分开,需要此行为。

预期的可观察行为是,如果构造函数抛出异常,则分配不会发生。在"优化"中不会出现这种情况。构造函数直接写入字段/堆栈插槽的版本。

在分配给本地变量时,您可以看到相同的IL:

  • 该变量已在
  • 之前声明并分配
  • 如果抛出异常,仍可访问该变量

不完全相同的问题,但有更多详细信息in this SO postEric Lippert's blog