嵌套的静态类以错误的顺序初始化?

时间:2015-07-27 17:27:40

标签: c# .net debugging

嵌套静态类在其父级之前初始化似乎存在问题。请参阅下面的示例,我添加了注释,以指示我期望事物初始化/调用的顺序以及实际的顺序。在这种情况下,我正在调用Test1.Test2.GetName(),所以我希望按以下顺序初始化静态类:Test1Test2

using System;
using System.Collections.Generic;

namespace ConsoleApplication1 {
    class Program {
        static void Main(string[] args) {
            Console.WriteLine(Test1.Test2.GetName());
            Console.ReadKey();
        }
    }

    public static class Test1 {
        // Actual Order: 2; Expected: 1
        private static string Name = "Test1";
        public static List<string> Names { get; private set; }

        // Actual Order: 3; Expected: 2
        static Test1() {
            Test1.Names = new List<string>(new string[] {
                Test2.GetName()
            });
        }

        public static class Test2 {
            // Actual Order: 1; Expected: 3
            private static string Name = Test1.Name.ToString() + "_Test2";

            // Actual Order: 4; Expected: 4
            public static string GetName() {
                return Name.ToString();
            }
        }
    }
}

我认为静态是在第一次触摸类时初始化的,但显然触及嵌套类并不首先初始化父级!这对我来说就像一个错误。它正在这样做:

Test2.Name - &gt; Test1.Name - &gt; Test1() - &gt; Test2.GetName() - &gt; Test2.Name

因此虽然Test2.Name是切入点,但理论上它并不是在需要的时候初始化的。

1 个答案:

答案 0 :(得分:4)

  

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

问题是嵌套类是其父级的静态成员。它完全是一个不同的阶级。它有一个nested attribute,但这仅用于会员可见性。

来自ECMA-335(CLI规范):

  

I.8.11.5嵌套类型定义
  嵌套类型定义与顶级类型定义相同,但有一个例外:顶级   type具有visibility属性,而嵌套类型的可见性与可见性相同   封闭式。

因此,行为是正确的。在调用嵌套类时,文档不需要初始化父类。无论如何,您应该注意应该避免使用嵌套的公共类,就像公共字段一样,因为这不是很好的封装。嵌套类应主要用于实现细节,并从外部隐藏。

如果嵌套类要求首先初始化其父类,则可以在其静态构造函数中显式强制它:

static Test2()
{
    RuntimeHelpers.RunClassConstructor(typeof(Test1).TypeHandle);
}

这里的含义非常明确。

但这不会使你的例子有效,因为它有一个循环依赖:

  • Test1静态构造函数调用Test2.GetName(),这意味着它将触发Test2的初始化
  • Test2静态构造函数(隐式)调用Test1.Name.ToString() + "_Test2",这将触发Test1的初始化

无论哪种方式,它都不会起作用,你必须修复该代码。