12

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.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
rabashani
  • 1,443
  • 2
  • 14
  • 22

6 Answers6

11

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

Gishu
  • 134,492
  • 47
  • 225
  • 308
  • It is legal to pass an as-yet uninitialized variable or field as an `out` parameter to an external or virtual method, even though the compiler is required to ensure that it's initialized before doing so (the other method could be written in a language which allows `out` parameters to be read before they're written). Since the compiler has to insert initialization code in that scenario, it would almost certainly have to be able to be able to do so in any scenario, if its implementers were so inclined. – supercat Dec 05 '12 at 22:40
  • Curious, why doesn't C# compiler implicitly insert `: this()` in such cases? – Vlad Feb 13 '17 at 13:29
  • 1
    @Vlad Because fields would potentially be initialized twice. Once by the base constructor call and another time by the user's constructor (if the user were to initialize a field). Daniel Brückner has an answer here that explains this. – Alex Jorgenson Aug 06 '18 at 16:54
6

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.

Daniel Brückner
  • 59,031
  • 16
  • 99
  • 143
  • It's interesting to note that while expressions of the form `structVar = structExpr` generally overwrite all the fields of the former struct with the corresponding fields of the latter, that is not the case with `structVar = new StructType(params);` Expressions of that form will sometimes make a temporary, pass it to the constructor, and then copy it to the indicated variable, but they will sometimes simply call the constructor, with the affected variable effectively passed as a `ref` parameter (which isn't zeroed out first). – supercat Dec 06 '12 at 23:05
5

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.

Brijesh Mishra
  • 2,738
  • 1
  • 21
  • 36
5

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.

RossFabricant
  • 12,364
  • 3
  • 41
  • 50
2
public struct Direction
{
    public int Azimuth { get; private set; }

    public Direction(int azimuth) : this()
    {
        Azimuth = azimuth;
    }
}
Konstantin Tarkus
  • 37,618
  • 14
  • 135
  • 121
-1

You need to initialize the field, and not via the property.

leppie
  • 115,091
  • 17
  • 196
  • 297