C#中跨类的静态变量初始化顺序是什么? [英] What is the static variable initialization order across classes in C#?

查看:164
本文介绍了C#中跨类的静态变量初始化顺序是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

DependencyProperty.AddOwner MSDN页面提供了一个包含两个示例类具有静态成员,并且一个类的成员依赖于另一类的成员进行初始化。我认为MSDN是错误的-静态变量的初始化顺序在C#中不可靠就像在C ++中一样或在其他任何地方。我可能错了,因为WPF库本身是用这种方式编写的,并且可以正常工作。我想念什么? C#编译器怎么可能知道安全的初始化顺序?

解决方案

对于一种类型,可以依赖于正在初始化的另一种类型,因此,



基本上,这很好:

  public class Child 
{
static Child(){} //添加了静态构造函数以提高可预测性
public static readonly int X = 10;
}

公共类Parent
{
static Parent(){} //添加了静态构造函数以提高可预测性
public static readonly int Y = Child 。X;
}

结果是明确的。 Child 的静态变量初始值设定项是在首次访问该类中的任何静态字段之前执行的,按照规范的10.5.5.1节。



这不是:

 公共班级儿童
{
public static readonly int Nasty = Parent.Y;
public static readonly int X = 10;
}

公共类父级
{
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 的初始化将意识到 Parent 需要初始化,但是CLR知道它已经被初始化,因此继续进行,导致第一组数字-因为 Child.X 最终在其值用于 Parent.Y之前被初始化。 code>。



访问 Child.Nasty 将开始初始化 Child 首先,然后它将开始初始化 Parent Parent 的初始化将意识到 Child 需要初始化,但是CLR知道它已经被初始化了,所以继续进行,导致第二组数字。



请勿这样做。






编辑:好的,如所承诺的那样,更详细的解释。



何时初始化类型?



如果类型具有静态构造函数,则只会在首次使用它时才初始化
(引用静态成员时,或创建实例时使用
)。如果没有具有静态的
构造函数,则可以更早对其进行初始化。从理论上讲,它也可以稍后初始化
。从理论上讲,您可以在不初始化静态变量的情况下调用构造函数或
a静态方法-但是
必须在引用静态变量之前对其进行初始化。



初始化期间会发生什么?



首先,所有静态变量都将收到其默认值(0,空
等)。



然后,以文本
顺序初始化该类型的静态变量。如果静态变量的初始值设定项表达式要求
另一种类型进行初始化,则该另一种类型将在赋值变量值之前完全初始化
-
除非第二种类型已经被初始化(由于循环依赖
)。本质上,类型可以是:




  • 已初始化

  • 当前正在初始化

  • 未初始化



仅当类型未初始化时才触发初始化。
这意味着,当存在循环依赖性时,
可能会在分配初始值
之前观察静态变量的值 。这就是我的孩子 / 父母示例所显示的。



在执行完所有静态变量初始化器后,将执行静态
构造函数。



有关所有这些的更多详细信息,请参见C#规范的10.12节。 p>




受大众欢迎,这是我的原始答案,当我认为问题与静态变量的初始化顺序有关时一个类



静态变量按照C#规范的10.5.5.1节以文本顺序初始化:


类的静态字段变量初始化器
对应于一系列
赋值,这些赋值以它们出现的
文本顺序执行在
类声明中。


请注意,部分类型使此操作更加棘手,因为没有一个规范的文本顺序课。


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?

解决方案

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:

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;
}

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:

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;
}

In this latter case, you either end up with Child.Nasty=0, Parent.Y=10, Child.X=10 or Child.Nasty=0, Parent.Y=0, Child.X=10 depending on which class is accessed first.

Accessing Parent.Y first will start initializing Parent first, which triggers the initialization of Child. The initialization of Child will realise that Parent 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 - because Child.X ends up being initialized before its value is used for Parent.Y.

Accessing Child.Nasty will start initializing Child first, which will then start to initialize Parent. The initialization of Parent will realise that Child 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:

  • Already initialized
  • Being initialized at the moment
  • Not initialized

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:

The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.

Note that partial types make this trickier as there's no one canonical "textual order" of the class.

这篇关于C#中跨类的静态变量初始化顺序是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆