Search code examples
c#object-initializers

C# The order of fields initialization


I create objects by initializing the fields in this way:

class Example
{
    public int a;
    public int b;
}

var obj = new Example
{
    a = stream.ReadInt(),
    b = stream.ReadInt()
};

Is it always for field "a" to be initialized before field "b"? Otherwise, an unpleasant error can occur when the values from the stream are subtracted in a different order. Thanks!

UPD: In the comments, many did not understand what I mean. I will clarify the question. Do these records always be identical in behavior on different (.NET, Mono, etc) compilers?

First:

var obj = new Example
{
    a = stream.ReadInt(),
    b = stream.ReadInt()
};

Second:

var a = stream.ReadInt();
var b = stream.ReadInt();

var obj = new Example
{
    a = a,
    b = b
};

Solution

  • IMHO, the relevant part of the C# language specification is reasonably clear. It could be less vague, but I don't see a way to interpret it that would allow for out-of-order initialization:

    An object initializer consists of a sequence of member initializers

    [Emphasis mine]. The word "sequence" necessarily implies an order. Maybe that doesn't seem normative, but their example does:

    An instance of Point can be created and initialized as follows:

    Point a = new Point { X = 0, Y = 1 };
    

    which has the same effect as

    Point __a = new Point();
    __a.X = 0;
    __a.Y = 1;
    Point a = __a;
    

    If a compiler author were to reorder the assignments, the program that they output would not comply with the above example.

    More generally, it's informative to look at the rest of the language in that section, as the language designers went to great pains to make sure the feature worked intuitively, including for nested assignments with object initializers to only assign a fully-formed object to the parent property.

    All that said, it really shouldn't matter. If you have a class where the order of assignments to two or more properties affects the final outcome, you've got a pretty hazardous class on your hands. Such design ought to be avoided at all costs, as it is way too easy to break in any case, even when the compiler rules for object initialization are reasonably clear.