Reputation: 11273
This question is not about how to initialize backing fields...
Lets say given this class:
public class Test
{
public int PropertyA { get; set; }
public int PropertyB { get; set; }
private int _propertyC;
public int PropertyC { get { return _propertyC; } set { _propertyC = value; } }
}
There are a number of properties defined, both automatically and explicitly implemented.
Lets take a closer look at how PropertyA
gets compiled (64-bit debug). The MSIL output is this:
.field private int32 'k__BackingField' .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) .property instance int32 PropertyA() { .get instance int32 TestCode.Test::get_PropertyA() .set instance void TestCode.Test::set_PropertyA(int32) } // end of property Test::PropertyA .method public hidebysig specialname instance int32 get_PropertyA() cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldfld int32 TestCode.Test::'k__BackingField' IL_0006: ret } // end of method Test::get_PropertyA .method public hidebysig specialname instance void set_PropertyA(int32 'value') cil managed { .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 ) // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: stfld int32 TestCode.Test::'k__BackingField' IL_0007: ret } // end of method Test::set_PropertyA
Which is pretty basic, it defines the backing field, the property and then the get_
and _set
methods for that property that load or set the backing field.
What I don't get (and I've taken for granted up until now), is that this is a perfectly legal constructor:
public Test()
{
Debug.WriteLine($"{PropertyA.ToString()}");
Debug.WriteLine($"{_propertyC.ToString()}");
}
While this is obviously a compiler error:
public Test()
{
int i;
Debug.WriteLine($"{i.ToString()}");
}
Which, as expected, gives CS0165 "Use of unassigned local variable 'i'". In doing some research for this and digging through the ECMA Spec, and the Microsoft C# spec (5.0 is the last formal document, 6.0 seems to be loosely distributed in the Roslyn project) and I can't find anything related to the initialization of fields.
I did find this reference from VS2003 that eludes to class fields being initialized to the default
value for the type, but it suggests that this is part of the language and not the runtime.
So the question is... Does the runtime perform the initialization of the fields, or am I missing something in the MSIL from the compiler that is initializing these values? I'm assuming the compiler does this otherwise I would expect the same CS0165 in both the example constructors.
Upvotes: 3
Views: 289
Reputation: 149518
Does the runtime perform the initialization of the fields, or am I missing something in the MSIL from the compiler that is initializing these values?
Part §5.2 and §5.3 of the specification talk about default values and definite assignment, respectively.
A quote from the spec (§5.2):
Initialization to default values is typically done by having the memory manager or garbage collector initialize memory to all-bits-zero before it is allocated for use. For this reason, it is convenient to use all-bits-zero to represent the null reference.
This goes on to show the memory manager and GC take care of default value initialization.
Upvotes: 1