初始化顺序错误的嵌套静态类
本文关键字:嵌套 静态类 错误 顺序 初始化 | 更新日期: 2023-09-27 18:04:51
嵌套静态类在其父类之前初始化似乎存在问题。请参阅下面的示例,我包含了注释来指示我期望初始化/调用的顺序,以及实际的顺序。在本例中,我调用Test1.Test2.GetName()
,因此我希望静态类按照以下顺序初始化:Test1
, Test2
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();
}
}
}
}
我认为静态是初始化的第一次类被触摸,但显然触摸嵌套类不会首先初始化父类!我觉得这是个bug。它的作用是:
Test2.Name
-> Test1.Name
-> Test1()
-> Test2.GetName()
-> Test2.Name
因此,尽管Test2.Name
是入口点,但理论上,在需要它的时候,它并没有被初始化。
问题是嵌套类不是父类的静态成员。这是一个完全不同的班级。它有一个在创建第一个实例或引用静态成员之前,自动调用静态构造函数初始化类。
nested
属性,但这只是为了成员可见性的目的。
来自ECMA-335 (CLI规范):
I.8.11.5嵌套类型定义
嵌套类型定义与顶级类型定义相同,但有一个例外:顶级类型定义类型具有可见性属性,而嵌套类型的可见性与的可见性相同封闭类型。
因此,行为是正确的。文档不要求在调用嵌套类时初始化父类。无论如何,您应该注意应该避免嵌套的公共类,就像公共字段一样,因为这不是良好的封装。嵌套类应该主要用于实现细节,并对外部隐藏。
如果一个嵌套类需要先初始化它的父类,你可以在它的静态构造函数中显式地强制它:
static Test2()
{
RuntimeHelpers.RunClassConstructor(typeof(Test1).TypeHandle);
}
这里的意思非常清楚。
但这不会使你的例子有效,因为它有一个循环依赖:
-
Test1
静态构造函数调用Test2.GetName()
,这意味着它将触发Test2
的初始化 -
Test2
静态构造函数(隐式)调用Test1.Name.ToString() + "_Test2"
,这将触发Test1
的初始化
无论哪种方式,它都不能工作,你必须修复代码