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

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

问题描述

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

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.

基本上没问题:

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 节.

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.

这不是:

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=0Parent.Y=10Child.X=10 Child.Nasty=0, Parent.Y=0, Child.X=10 取决于首先访问哪个类.

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.

首先访问Parent.Y会先初始化Parent,从而触发Child的初始化.Child 的初始化会意识到Parent 需要被初始化,但是CLR 知道它已经被初始化了,所以不管了,继续,导致第一组数字——因为 Child.X 在其值用于 Parent.Y 之前最终被初始化.

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.

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

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.

不要这样做.

好的,更详细的解释,正如承诺的那样.

Okay, more detailed explanation, as promised.

什么时候初始化类型?

如果一个类型有一个静态构造函数,它只会被初始化首次使用时(引用静态成员时,或创建实例时).如果它没有静态构造函数,它可以提前初始化.理论上也可以稍后初始化;理论上你可以调用构造函数或没有初始化静态变量的静态方法 - 但是它必须在引用静态变量之前被初始化.

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.

初始化期间会发生什么?

首先,所有静态变量都接收它们的默认值(0, null等).

First, all static variables receive their default values (0, null etc).

然后在textual中初始化类型的静态变量命令.如果静态变量的初始化表达式需要要初始化的另一种类型,则该另一种类型将是在分配变量值之前完全初始化 -除非第二种类型已经被初始化(由于循环依赖).本质上,类型是:

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:

  • 已经初始化
  • 目前正在初始化
  • 未初始化

只有在类型未初始化时才会触发初始化.这意味着当存在循环依赖时,有可能在其初始值具有之前观察静态变量的值被分配.这就是我的 Child/Parent 示例显示的内容.

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.

有关所有这些的更多详细信息,请参阅 C# 规范的第 10.12 节.

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:

静态变量按文本顺序初始化,如 C# 规范的第 10.5.5.1 节所述:

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天全站免登陆