Order of operations using Object Initializer Syntax
Asked Answered
C

1

38

Does the order in which I set properties using the object initializer syntax get executed in the exact same order?

For instance if I do this:

var s = new Person { FirstName = "Micah",
                     LastName = "Martin",
                     IsLoaded = true
                   }

will each property get set in the same order?

Confabulation answered 30/1, 2009 at 14:14 Comment(0)
S
57

Yes.

Apologies for getting interrupted (I have to actually do some work every so often). The spec doesn't explicitly say it, but it makes it pretty clear IMO in section 7.6.10.2:


An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas.

(Note the word "sequence" here, rather than "set". I personally think that's significant, as a sequence is ordered.)

The following class represents a point with two coordinates:

public class Point
{
    int x, y;
    public int X { get { return x; } set { x = value; } }
    public int Y { get { return y; } set { y = value; } }
}

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;

where __a is an otherwise invisible and inaccessible temporary variable.


EDIT: I've had a response from Mads Torgersen, who has basically said that anything which can be done now will preserve the order. There may be some oddities in future where the order is not preserved in weird cases where you're doing something other than setting a property/field, but that will depend on where the language goes.

It's worth pointing out that there are actually lots of steps going on here - there's the order of execution of the evaluation of the arguments (i.e. the RHS bits) and the order of execution of the assignments. For example, if you have:

new Foo
{
    A = X,
    B = Y
}

all the following orders are possible while still maintaining the order of the actual property execution (A and B):

  • Evaluate X, assign to A, evaluate Y, assign to B
  • Evaluate X, evaluate Y, assign to A, assign to B
  • Evaluate Y, evaluate X, assign to A, assign to B

I believe the first option is the one actually taken, but this was just to demonstrate that there's more to it than meets the eye.

I would also be very wary of actually writing code which depends on this...

Somewise answered 30/1, 2009 at 14:16 Comment(9)
My biggest concern is that the assignments occur in the order I list them in. I'm not concerned about the right-side evaluation order as much as I am about the actual left-side assignment order.Confabulation
Hmm. In my case my concerns are the other way round. The assignment order is pretty irrelevant for me as i just need the object / struct to be initialized. However the order of evaluation would be important since i use a BinaryReader and each field is set by a ReadSingle() call. If the order is not guaranteed I better avoid the object initializer completely. Better safe than sorry. Such syntactic sugar is pretty useless if it's not properly specified ^^. Are there actually any documented cases where the evaluation order was not preserved?Tridimensional
@Bunny83: Not that I'm aware of, and I'm very confident that the order is preserved, and that that's the intention of the spec - it's just not as explicit as it could be.Somewise
Not sure the ordering is still preserved after creation of the "init" accessor.Opec
@sjb-sjb: I don't follow you. What exactly do you mean by 'after creation of the "init" accessor'? Do you mean that the properties might be assigned in a different order? I'm pretty sure the spec guarantees that's not the case. Or are you talking about something else?Somewise
@JonSkeet I guess I'm wondering whether the addition of "init" to the language had any impact on the order of execution of the properties. Some of them are now invoking "set" while others invoke "init". Most likely no change would be my guess --Opec
@JonSkeet I see that "Property init accessors will be emitted as a standard set accessor with the return type marked with a modreq of IsExternalInit", which seems to answer the question. I'd like to identify init accessors by reflection though and I don't know enough about modreq to see how to do it.Opec
I found it here: #69852964Opec
"I would also be very wary of actually writing code which depends on this" One trouble is when using static code analysis you get forced into using it due to IDE0017 If the initialisation comes from a BinaryReader then the possibility of Evaluate Y evaluate X will break thingsDrumfire

© 2022 - 2024 — McMap. All rights reserved.