More on inline initialization (answer)

Well, due to overwhelming feedback for the previous post, here’s the answer: 0.

Now the most interesting part: why?

When you use inline initialization, compiler generates a static constructor for you, and does all the initialization there. It looks like, it’s not smart enough to pick this kind of dependencies, and simply initializes fields in the order they’ve been declared in the class’ body. That’s why, by the time Field is initialized, _height has value 3, but _width is still 0. If you wanted to overcome this, you’d have to use const instead of readonly (that’s an option only for primitives and strings), or move dependant properties to some other class (for example private class). Or if slight performance decrease during creation of your class’ instances is not going to be a problem, use explicit static constructor.

Comments

Nicholas Carey says:

It’s not that the compiler isn’t smart enough to note the apparent dependencies and execute the initializers in dependency order. The C# standard, ISO 23270:2006), freely available at standards.iso.org/…/c042926_ISO_IEC_23270_2006(E).zip requires the behaviour you observed. The Standard (section 17.4) mandates the following sequence of initialization events for a class:

1. All static fields are initialized with default value for the field’s type.
2. All static field initializers are executed in textual order. If the class is defined as ‘partial’ and consists of multiple partial declarations, the order in which the initializers for each such partial part is executed is unspecified (e.g., is implementation-dependent), even if all the partial declarations are in the same compilation unit (source file).
3. The static constructor for the class, if one exists, is then executed.

It is important to note that these steps occur only at some “implementation-dependent time prior to the first use of the class.”

Each time a class is instantiated, a similar process occurs to intialize the instance fields:

1. initialize each instance field with the default value for that field’s type.
2. execute each instance field’s initializer in textual order.
3. execute the instance constructor.

Note that in each case, the implementation is likely to collapse steps 1 and 2 — if a field has an explicit initializer, the IL is unlikely to first set it to the default value for that type prior to executing the initializer.