静态字段初始化在 C# 中是如何工作的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/710793/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 14:21:24  来源:igfitidea点击:

How does static field initialization work in C#?

c#compiler-construction

提问by Prankster

Should static field initialization be completed before constructor is called?

是否应该在调用构造函数之前完成静态字段初始化?

The following program provides output that seems incorrect to me.

以下程序提供了对我来说似乎不正确的输出。

new A()
_A == null
static A()
new A()
_A == A

The code:

编码:

public class A
{
    public static string _A = (new A()).I();

    public A()
    {
        Console.WriteLine("new A()");
        if (_A == null)
            Console.WriteLine("_A == null");
        else
            Console.WriteLine("_A == " + _A);
    }

    static A()
    {
        Console.WriteLine("static A()");
    }

    public string I()
    {
        return "A";
    }
}

class Program
{
    static void Main(string[] args)
    {
       var a = new A();
    }
}

采纳答案by Reed Copsey

This is correct.

这是对的。

Your static initializers, then the static constructor is run before your standard constructor, but when it runs, it's using new A(), so passing through your non-static constructor path. This causes the messages you see.

您的静态初始值设定项,然后静态构造函数在您的标准构造函数之前运行,但是当它运行时,它使用 new A(),因此通过您的非静态构造函数路径。这会导致您看到的消息。

Here is the full path of execution:

完整的执行路径如下:

When you first call var a = new A();in your program, this is the first time A is accessed.

当您第一次调用var a = new A();程序时,这是第一次访问 A。

This will fire off the static initialization of A._A

这将触发静态初始化 A._A

At this point, A._A constructs with _A = (new A()).I();

此时,A._A 构造为 _A = (new A()).I();

This hits

这命中


Console.WriteLine("new A()");
if (_A == null)
    Console.WriteLine("_A == null");        

since at this point, _A hasn't been set with the returned, constructed type (yet).

因为此时,_A 还没有被设置为返回的构造类型(还)。

Next, the static constructor A { static A(); }is run. This prints the "static A()" message.

接下来,A { static A(); }运行静态构造函数。这将打印“静态 A()”消息。

Finally, your original statement (var a = new A();) is executed, but at this point, the statics are constructed, so you get the final print.

最后,您的原始语句 ( var a = new A();) 已执行,但此时已构造静态,因此您将获得最终打印。

回答by XOR

Yes, static fields initialization should complete before constructor is called. But you put compiler in the unnormal situation and it just can't obey this rule.

是的,静态字段初始化应该在调用构造函数之前完成。但是您将编译器置于异常情况下,它就无法遵守此规则。

This is interesting trick, but it's not gonna happen in normal application.

这是一个有趣的技巧,但它不会发生在正常的应用程序中。

回答by Mitchel Sellers

I actually believe that it is doing what you think. Your test makes it hard to tell.

我实际上相信它正在按照您的想法行事。你的测试很难说。

Your initalization for _A

您对 _A 的初始化

public static string _A = (new A()).I();

First creates a new instance of A, thus your writings of new A() and _A = null. Because it was null when it started, as this is the initialization. Once initalized, the static constructor is called, which returns the new instance.

首先创建 A 的一个新实例,因此你写的 new A() 和 _A = null。因为它在启动时为空,因为这是初始化。一旦初始化,静态构造函数被调用,它返回新的实例。

回答by bruno conde

It seems the compiler is doing the expected.

似乎编译器正在做预期的事情。

1st - All static code is executed (fields first, then static constructor) in the class:

1st - 在类中执行所有静态代码(首先是字段,然后是静态构造函数):

public static string _A = (new A()).I();

// and

static A()
{
    Console.WriteLine("static A()");
}

2nd - Class constructor is called:

2nd - 类构造函数被调用:

public A()
{
    Console.WriteLine("new A()");
    if (_A == null)
        Console.WriteLine("_A == null");
    else
        Console.WriteLine("_A == " + _A);
}

You ask why this is possible. Well, in my opinion, an instance doesn't absolutely require that all class variables are initialized upon creation. It just requires they must exist. I think this particular case supports this thought because an instance is created before all static initialization is done.

你问为什么这是可能的。好吧,在我看来,一个实例并不绝对要求所有类变量在创建时都被初始化。它只是要求它们必须存在。我认为这个特殊情况支持这个想法,因为在所有静态初始化完成之前创建了一个实例。

回答by Hugh Robinson

One extra side note - the C# specification (I'm looking at 4.0, but it's there in 3.0 too) says in 10.5.5.1 Static Field Initialization:

一个额外的旁注 - C# 规范(我正在查看 4.0,但它也在 3.0 中)在 10.5.5.1 静态字段初始化中说:

If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.

如果类中存在静态构造函数(第 10.12 节),则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,在第一次使用该类的静态字段之前的依赖于实现的时间执行静态字段初始值设定项。

You have a static constructor, so the "Otherwise" clause does not apply. But I think it's relevant information to your question to know that if you don't have a static constructor, the static field initializers can be executed 'at an implementation-dependent time'. This could matter if your static field initializer is doing some type of data initialization or object creation which you rely on without accessing the static field itself.

您有一个静态构造函数,因此“Otherwise”子句不适用。但是我认为如果您没有静态构造函数,则可以在“依赖于实现的时间”执行静态字段初始值设定项,这是与您的问题相关的信息。如果您的静态字段初始值设定项正在执行某种类型的数据初始化或对象创建,而无需访问静态字段本身,则这可能很重要。

It is esoteric, I guess, but I saw it happen today as the 'implementation-dependent time' appears to have changed between C# 3.0 and 4.0 - at least for the situation I was looking at. The easy solution of course is simple - just add a static constructor...

我想这是深奥的,但我今天看到它发生了,因为“依赖于实现的时间”似乎在 C# 3.0 和 4.0 之间发生了变化——至少对于我所看到的情况。简单的解决方案当然很简单 - 只需添加一个静态构造函数......