A value type local variable (e.g. S s;
given struct S{}
) is initialized though the invocation of its constructor (e.g. a = new S(11)
), if S
declares a constructor with int
parameter. Then new S(11)
compiles to:
ldloca.s V_0
ldc.i4.s 11
call instance void S::.ctor(int32)
However when s
is a field (e.g. class C { S s;
), then it is not initialized in the same way. Regarding the following instance method of class C
: void setS(int n) { s = new S(n); }
it will compile to:
ldarg.0
ldarg.1
newobj instance void S::.ctor(int32)
stfld valuetype S C::s
I was expecting that it would compile to the following code, which is more close to the case of a local variable:
ldarg.0
ldflda valuetype S C::s
ldarg.1
call instance void S::.ctor(int32)
Moreover, if I am clearly understanding, the newobj instance void S::.ctor(int32)
has higher overhead and burdens GC. Am I correct?
Why, C# compiler uses for value type fields a different approach than used for local variables?
Basically, this behaviour is required in order to separate the constructor call from the assignment.
The expected observable behaviour is that if a constructor throws an exception, the assignment doesn't take place. That won't be the case in the "optimized" version where the constructor writes directly to the field/stack slot.
You can see the same IL when assigning to a local variable if:
Not quite the same question, but there's more detail in this SO post and on Eric Lippert's blog.
See more on this question at Stackoverflow