【问题标题】:Which static class initializes first?哪个静态类首先初始化?
【发布时间】:2011-03-10 14:13:49
【问题描述】:

如果我们的项目中还有一个静态类,哪个静态类首先初始化?

例如:下面的代码给出了空异常。

class Program
    {
        static void Main(string[] args)
        {
            First.Write();
            Second.Write();
        }
    }
    static class First
    {
        public static int[] firstArray = new int[20];
        public static int[] secondArray = Second.secondArray;
        public static void Write()
        {
            Console.WriteLine(firstArray.ToString());
            Console.WriteLine(secondArray.ToString());
        }
    }
    static class Second
    {
        public static int[] firstArray = First.firstArray;
        public static int[] secondArray = new int[30];
        public static void Write()
        {
            Console.WriteLine(firstArray.ToString());
            Console.WriteLine(secondArray.ToString());
        }
    }

如果你注意,你会看到如果First 类会初始化自己,那么SecondsecondArray 字段将为空。但是如果Second 类首先初始化,那么SecondfirstArray 将为空。我试图告诉哪个初始化首先产生不同的结果。

我认为这是关于我的项目的抽象问题。我在尝试了解为什么会得到意外结果时遇到它。

【问题讨论】:

    标签: c# .net initialization static-classes


    【解决方案1】:

    First 将开始初始化,分配firstArray,然后注意它需要初始化Second 以获得secondArray 的初始值。

    Second 将开始初始化,然后注意它需要 First 进行初始化。但是,CLR 会注意到 First 已经在当前线程中初始化,所以它不会阻塞。 Second的初始化将完成,然后First的初始化将完成。

    幸运的是,Second 需要的字段已经分配,​​所以“正确的事情”发生了。

    如果First 实际上首先开始初始化,那就太好了。但是,由于这两个类都没有静态构造函数,因此Second 可能会首先开始初始化......然后它会开始初始化First,这会发现Second 已经在初始化并采用@987654334 First.secondArray 的 @ 的当前值 (null)。这将是一件坏事。请注意,没有静态构造函数的类型的初始化时间有changed in .NET 4 - 不是以破坏规范的方式,但可能以现有的代码破坏方式。

    如果FirstSecond 都有静态构造函数,那么First 将首先被初始化,因为这是Main 接触的第一个类。

    答案的寓意:不要这样做。相互引用的类型初始化器非常容易出错。另一个示例,请参阅 Eric Lippert 和 Neal Gafter 在 NDC 2010 的演讲“C# Puzzlers”,可以在 NDC video page 上查看。

    【讨论】:

    • 标准是否保证这个订单?我的猜测是,每个类在第一次访问之前都会在一些未定义的地方初始化,这会将其变成一个随机解析的依赖循环。
    • @Tim:我已经更新了我的答案——没有静态构造函数,顺序确实是未定义的。
    • 将调试器附加到 VS2005 时,发生了一件坏事 - Second.firstArray 设置为 null
    • 在这里,我认为其中一些谜题纯粹是学术性的:P
    • @Jon Skeet:经过几次测试,我发现更改写入方法的顺序不会改变结果。第一类构造函数首先工作,然后再次抛出空异常。
    【解决方案2】:

    我不相信首先初始化哪种静态类型有任何保证。为了确保以这种方式正确初始化字段,您需要添加一个静态构造函数,例如:

    static class Second
    {
        public static int[] firstArray = First.firstArray;
        public static int[] secondArray = new int[30];
    
        static Second() { }
    
        public static void Write()
        {
            Console.WriteLine(firstArray.ToString());
            Console.WriteLine(secondArray.ToString());
        }
    }
    

    现在,当你再次运行相同的东西时,它就可以工作了......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-14
      • 1970-01-01
      • 2014-02-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多