11

以下程序的输出是:

Non-Static
Static
Non-Static

这是编译器错误吗?我期望:

Static
Non-Static
Non-Static

因为我认为静态构造函数总是在非静态构造函数之前调用。

我在 Visual Studio 2010 中使用 .net 3.5 和 .net 4.0 对此进行了测试。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StaticConstructorBug
{
    class Program
    {
        static void Main(string[] args)
        {
            var mc = new MyClass();

            Console.ReadKey();
        }
    }

    public class MyClass
    {
        public MyClass()
        {
            Console.WriteLine("Non-static");
        }

        static MyClass()
        {
            Console.WriteLine("Static");
        }

        public static MyClass aVar = new MyClass();
    }
}
4

4 回答 4

11

参见ECMA 334 §17.4.5.1:

17.4.5.1 静态字段初始化

类声明的静态字段变量初始值设定项对应于一系列赋值,这些赋值序列按照它们在类声明中出现的文本顺序执行。如果类中存在静态构造函数(第 17.11 节),则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,静态字段初始化器在第一次使用该类的静态字段之前的依赖于实现的时间执行

具体来说:“静态字段初始化程序的执行发生在执行该静态构造函数之前”。

static MyClass aVar必须在静态构造函数执行之前进行初始化(或者,至少它必须以这种方式出现)。如果没有该静态成员,则应在任何非静态构造函数之前调用静态构造函数。

如果你仍然想要一个MyClass单例,你可以把它放在一个容器类中并使用它来引用它,例如:

public static class MyClassSingleton
{
    public static MyClass aVar = new MyClass();
}
于 2010-05-27T23:10:02.460 回答
5

它是由线引起的public static MyClass aVar = new MyClass();

事实上,它aVar = new MyClass();是在静态构造函数之前的。所以你的静态构造函数:

static MyClass() {
    Console.WriteLine("Static");
}

改为:

static MyClass() {
    aVar = new MyClass(); // this will run instance contstructor and prints "Non-Static"
    Console.WriteLine("Static");
}
于 2010-05-27T23:12:29.277 回答
1

public static MyClass aVar = new MyClass();是您的静态构造函数的一部分。如果你用反射器看它,你会看到以下内容:

static MyClass()
{
    aVar = new Program.MyClass();
    Console.WriteLine("Static");
}

所以你的结果现在应该很明显了。

于 2010-05-27T23:03:27.127 回答
0

从 MSDN链接

在创建第一个实例或引用任何静态成员之前,会自动调用静态构造函数来初始化类。

我猜这是因为最后一行实例的静态实例化,但根据 MSDN,静态构造函数应该在调用第一个实例之前发生。

于 2010-05-27T23:04:01.070 回答