DependencyProperty.AddOwner MSDN页面提供了一个包含两个带有静态成员的类的示例,其中一个类的成员依赖于另一个类的成员进行初始化。我认为MSDN是错误的 - 在C#以及任何其他地方,静态变量的初始化顺序是不可靠的。我可能是错的,因为WPF库本身就是这样编写的,而且它运行得很好。我漏掉了什么?C#编译器如何知道安全的初始化顺序呢?
DependencyProperty.AddOwner MSDN页面提供了一个包含两个带有静态成员的类的示例,其中一个类的成员依赖于另一个类的成员进行初始化。我认为MSDN是错误的 - 在C#以及任何其他地方,静态变量的初始化顺序是不可靠的。我可能是错的,因为WPF库本身就是这样编写的,而且它运行得很好。我漏掉了什么?C#编译器如何知道安全的初始化顺序呢?
如果不会陷入死循环,一个类型依赖于另一个类型的初始化是可以接受的。
基本上这是可行的:
public class Child
{
static Child() {} // Added static constructor for extra predictability
public static readonly int X = 10;
}
public class Parent
{
static Parent() {} // Added static constructor for extra predictability
public static readonly int Y = Child.X;
}
结果是定义明确的。Child
类的静态变量初始化器在根据规范第10.5.5.1节中任何静态字段的首次访问之前执行。
这个不是。
public class Child
{
public static readonly int Nasty = Parent.Y;
public static readonly int X = 10;
}
public class Parent
{
public static readonly int Y = Child.X;
}
在后一种情况下,你将得到 Child.Nasty=0
、Parent.Y=10
、Child.X=10
或者 Child.Nasty=0
、Parent.Y=0
、Child.X=10
的值,取决于首先访问哪个类。Parent.Y first
的访问会先初始化 Parent
,然后触发 Child
的初始化。而当Child.X
被初始化之前就使用了它的值来赋给 Parent.Y
,所以 Child
知道必须初始化 Parent
,但是CLR知道正在初始化 Parent
,所以继续执行,导致出现了第一组数字。而访问 Child.Nasty
会先初始化 Child
,然后开始初始化 Parent
。在这种情况下,初始化 Parent
将意识到必须初始化 Child
,但CLR知道正在初始化 Child
,所以继续执行,导致出现第二组数字。 不要这样做。如果您关心顺序,您可以将代码放置在静态构造函数中。这是我注册依赖属性的地方。
不,我认为“unreliable”这个词在这里并不正确。
在真正的单线程场景中,当您的代码中访问类型的任何静态成员时,类的静态成员将被初始化。
我不了解c++,但是在多线程环境中只有在某些情况下,如果两个类型尝试访问共享资源并且该资源为静态资源,则无法确定哪个线程会胜出,也无法确定哪个线程会正确工作。
MSDN示例是正确的,它将正常工作。