I would like to try this code:
public struct Direction
{
private int _azimuth;
public int Azimuth
{
get { return _azimuth; }
set { _azimuth = value; }
}
public Direction(int azimuth)
{
Azimuth = azimuth
}
}
But it fails on compilation, I understand that struct need to init all its fields.
but i am trying to understand what happens under the CLR\IL hoods.
why it need all the fields before any other method\property\this etc.
Thanks.
Value Types are created on the stack (unless nested within a reference type) There is something about fields/locations on the stack that the CLR can't guarantee that they will be zeroed out (contrary to fields/locations on the managed heap which are guaranteed to be zeroed out). Hence they must be written to before being read. Otherwise it's a security hole.
The struct's default ctor (which takes no parameters and which you're not allowed to explicitly specify) zeroes out all fields of a struct and hence you can use a struct after you do.
new BimonthlyPairStruct()
However when you implement your parameterized ctor, you must ensure that all fields have been initialized - which is required for the CLR to pass your code as safe/verified .
See Also: CLR via C# 2nd Ed - Pg 188
This is because structs are derived from System.ValueType and not System.Object, System.ValueType implements default constructur which you cannnot override, this default constructer initializes all fields in struct with its default value. So if you are implementing any parameter contructor in your class you will also need t0 ensure you invoke system.ValueType default const. And to answer why it needs to init all its value this is because value are stored in stack memory.
This works:
public Direction(int azimuth)
{
_azimuth = azimuth;
}
From the spec:
Struct constructors are invoked with
the new operator, but that does not
imply that memory is being allocated.
Instead of dynamically allocating an
object and returning a reference to
it, a struct constructor simply
returns the struct value itself
(typically in a temporary location on
the stack), and this value is then
copied as necessary.
Basically, the compiler must see that every field gets initialized in the constructor so that it can copy those values, and it is not willing to examine calls to functions or properties.
I just found an explanation in the MSDN forum stating that this rule is enforced because zeroing out the memory is skipped if you use a none default constructor. So you will have to provide initialization values for all fields in order to avoid some fields containing random values. You achieve this easily be calling the parameter less default constructor, but at the cost of initializing some fields twice.
I cannot tell if this explanation is correct, but it sounds reasonable.
When you define a non-default initializer, C# requires you to set all fields because it
skips the zeroing of memory and lets you initialize it - otherwise you'd have to have a
double initialization performance hit. If you don't care about the (very slight)
performance hit you can always chain a call to the : this() initializer and then only
initialize selected fields.
public struct Direction
{
public int Azimuth { get; private set; }
public Direction(int azimuth) : this()
{
Azimuth = azimuth;
}
}
You need to initialize the field, and not via the property.