c# - Auto property initialization IL instruction order

问题描述:

I want to get the default value set on an auto property to do some IL weaving with Fody.

As I understand, the initialization is just a syntactic sugar that sets the backing field in the constructor. So I thought the default value is created with the instructions from the end of the last property's initialization to the stfld instruction that sets the backing field of the current property.

However this assumes the initialization is always done as the first thing in the constructor. Is that a correct assumption? Is there any edge cases to consider such as optimizations?

网友答案:

I found this pdf file titled Upcoming Features in C# which describes the new language features for C# 6.

Here is the section about auto property initializers (Emphasis is mine):

The initializer directly initializes the backing field; it doesn’t work through the setter of the autoproperty.

The initializers are executed in order as written, just as – and along with – field initializers.

Just like field initializers, auto-property initializers cannot reference ‘this’ – after all they are executed
before the object is properly initialized. This would mean that there aren’t a whole lot of interesting
choices for what to initialize the auto-properties to. However, primary constructors change that. Autoproperty
initializers and primary constructors thus enhance each other.

Since the field initializers and the auto property initializers are treated equally, the following section from C# specification should apply to the auto property initialization as well.

10.11.3 Constructor execution

Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor. This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed.

...

It is useful to think of instance variable initializers and constructor initializers as statements that are
automatically inserted before the constructor-body.

网友答案:

First, a general note: you speak of "the value" as though you could get it from analyzing the IL. This isn't true in general, because the expression could be anything, as long as it doesn't involve this. You can only get the instructions that calculate the value, which may be enough for your application. For an edge case, consider the fact that in particular, the expression may initialize fields other than the backing field of the property:

The semantics of this are predictable but not obvious: the default value of s is 0 (t has not been explicitly initialized at this point because initialization happens in declaration order), the default value of t is 2, and the default value of i is 1, with the twist that its initialization, if it occurs, also sets t and then s to 1. Deriving the values from the IL code in this case is not trivial, and even identifying the initializers requires that you consider which stfld/stsfld instructions assign to property backing fields, as opposed to any old field.

Speaking of trivial, if a property is initialized to the default value of the type, the compiler may elide generation of the property initialization altogether since it will be handled by newobj. On the IL level, the following may result in the same code:

int a { get; set; } = 3 / 4;

and

int a { get; set; }

This is an edge case in the sense that what looks like an initializer in code may not be present in the IL at all. If all you're interested in is the value, not whether an explicit initializer was used, this is of course no problem.