Why value type fields may be instantiated, instead of initialized?

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:

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:

ldflda    valuetype S C::s
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?

Jon Skeet

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:

  • The variable was already declared and assigned before
  • The variable is still accessible if an exception is thrown

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