First of all, try not to make an analogy between Class
and Struct
in C#. They are quite different.
Let's say I got the following code:
class MyClass
{
private int a = 0;
}
struct MyStruct
{
//private int a = 0; => this is not allowed
}
class Program
{
static void Main(string[] args)
{
var aCls=new MyClass();
var aStruct=new MyStruct();
}
}
When you check the il code,
class MyClass{...}
generated the following code:
.class private auto ansi beforefieldinit
Ctors.MyClass
extends [mscorlib]System.Object
{
.field private int32 a
.method public hidebysig specialname rtspecialname instance void
.ctor() cil managed
{
.maxstack 8
// [11 9 - 11 27]
IL_0000: ldarg.0 // this
IL_0001: ldc.i4.0
IL_0002: stfld int32 Ctors.MyClass::a
IL_0007: ldarg.0 // this
IL_0008: call instance void [mscorlib]System.Object::.ctor()
IL_000d: nop
IL_000e: ret
} // end of method MyClass::.ctor
} // end of class Ctors.MyClass
struct MyStruct{}
generated the following code:
.class private sealed sequential ansi beforefieldinit
Ctors.MyStruct
extends [mscorlib]System.ValueType
{
} // end of class Ctors.MyStruct
Based on observatons above:
1. MyClass genenerated a parameterless constructor.
2. The a=0
assignment will be put in the parameterless constructor.
3. There is no auto generated parameterless constructor for MyStruct
4. The a=0
assignment can not be directly put in MyStruct
. It won't compile.
Let's see what will happen when we new
them:
IL_0001: newobj instance void Ctors.MyClass::.ctor()
IL_0006: stloc.0 // aCls
// [22 13 - 22 40]
IL_0007: ldloca.s aStruct
IL_0009: initobj Ctors.MyStruct
The MyClass
will be ctored by newobj
while the MyStruct
will be ctored by initobj
.
Why call this()
solved? Actullay, it generated the following code:
IL_0000: ldarg.0 // this
IL_0001: initobj Ctors.RequestLog
I think we should not consider it parameterless constructor. It works very different from what you would expect a parameterless constructor do. It is just syntax sugar to clear state for value type.
Why should I to explicitly initialize all fields for struct
? Simply Safety.
More details can be found in the following quote:
Note Strictly speaking, value type fields are guaranteed to be 0/null when the value type
is a field nested within a reference type. However, stack-based value type fields are not
guaranteed to be 0/null . For verifiability, any stack-based value type field must be written
to prior to being read. If code could read a value type’s field prior to writing to the field,
a security breach is possible. C# and other compilers that produce verifiable code ensure
that all stack-based value types have their fields zeroed out or at least written to before
being read so that a verification exception won’t be thrown at run time. For the most part,
this means that you can assume that your value types have their fields initialized to 0 , and
you can completely ignore everything in this note.
by Jeffrey Richter CLR via C#.