DependencyProperty.AddOwner MSDN page offers an example with two classes with static members, and the member of one class depends on the member of the other class for initialization. I think MSDN is wrong - the initialization order of static variables is unreliable in C# just like it is in C++ or anywhere else. I'm probably wrong because the WPF library itself is written that way and it works just fine. What am I missing? How can C# compiler possibly know the safe initialization order?
相关问题
- Sorting 3 numbers without branching [closed]
- Graphics.DrawImage() - Throws out of memory except
- Why am I getting UnauthorizedAccessException on th
- 求获取指定qq 资料的方法
- How to know full paths to DLL's from .csproj f
It's fine for one type to depend on another type being initialized, so long as you don't end up in a cycle.
Basically this is fine:
The result is well-defined.
Child
's static variable initializers are executed prior to the first access to any static field in the class, as per section 10.5.5.1 of the spec.This isn't though:
In this latter case, you either end up with
Child.Nasty=0
,Parent.Y=10
,Child.X=10
orChild.Nasty=0
,Parent.Y=0
,Child.X=10
depending on which class is accessed first.Accessing
Parent.Y first
will start initializingParent
first, which triggers the initialization ofChild
. The initialization ofChild
will realise thatParent
needs to be initialized, but the CLR knows that it's already being initialized, so carries on regardless, leading to the first set of numbers - becauseChild.X
ends up being initialized before its value is used forParent.Y
.Accessing
Child.Nasty
will start initializingChild
first, which will then start to initializeParent
. The initialization ofParent
will realise thatChild
needs to be initialized, but the CLR knows that it's already being initialized, so carries on regardless, leading to the second set of numbers.Don't do this.
EDIT: Okay, more detailed explanation, as promised.
When is a type initialized?
If a type has a static constructor, it will only be initialized when it's first used (either when a static member is referenced, or when an instance is created). If it doesn't have a static constructor, it can be initialized earlier. In theory, it could also be initialized later; you could theoretically call a constructor or a static method without the static variables being initialized - but it must be initialized before static variables are referenced.
What happens during initialization?
First, all static variables receive their default values (0, null etc).
Then the static variables of the type are initialized in textual order. If the initializer expression for a static variable requires another type to be initialized, then that other type will be completely initialized before the variable's value is assigned - unless that second type is already being initialized (due to a cyclic dependency). Essentially, a type is either:
Initialization is only triggered if the type is not initialized. This means that when there are cyclic dependencies, it is possible to observe a static variable's value before its initial value has been assigned. That's what my
Child
/Parent
example shows.After all the static variable initializers have executed, the static constructor executes.
See section 10.12 of the C# spec for more details on all of this.
By popular demand, here was my original answer when I thought the question was about the initialization order of static variables within a class:
Static variables are initialized in textual order, as per section 10.5.5.1 of the C# spec:
Note that partial types make this trickier as there's no one canonical "textual order" of the class.
If you are concerned about the order you could always place your code in the static constructor. This is where I register my dependency properties.
No I think unreliable is not the correct word here.
In true single thread scenario, static members of class are initialized when any of static members of the type is first accessed in your code.
I am not aware of c++, but yes only in certain cases like in Multi threaded environment if two types trying to access shared resource and if that is static then its impossible to tell who will win and which one will work correct.
The MSDN Example is correct and that will work correctly.