我有一个课程如下:
static class Configuration
{
private static AppSettingsSection _appSettingsLogsSection;
static Configuration()
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
_appSettingsLogsSection = config.GetSectionGroup("Logs").Sections["appSettings"] as AppSettingsSection;
}
public static int LogSendIntervalMinutes = Convert.ToInt32(_appSettingsLogsSection.Settings["LogSendIntervalMinutes"]);
}
现在,根据我的理解,应该在第一次引用任何静态成员之前调用静态构造函数。但令人惊讶的是,它的表现并不像那样。当我从Main类引用 LogSendIntervalMinutes 时,不是触发静态构造函数,而是直接调用静态字段,从而导致NullReferenceException。
我在这里做错了什么,我的理解是否正确?
答案 0 :(得分:4)
在调用静态构造函数之前,始终初始化静态字段。您应该在静态构造函数中初始化LogSendIntervalMinutes
。我建议你甚至把它作为财产:
static class Configuration
{
private static AppSettingsSection _appSettingsLogsSection;
public static int LogSendIntervalMinutes { get; private set; }
static Configuration()
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
_appSettingsLogsSection = config.GetSectionGroup("Logs").Sections["appSettings"] as AppSettingsSection;
LogSendIntervalMinutes = Convert.ToInt32(_appSettingsLogsSection.Settings["LogSendIntervalMinutes"]);
}
}
来自C# language specification的引用(我强调了重点):
10.4.5.1静态字段初始化
类的静态字段变量初始值设定项对应于a 以文本顺序执行的分配顺序 它们出现在类声明中。 如果是静态构造函数 (第10.11节)存在于类中,执行静态字段 初始化程序在执行该静态之前立即发生 构造函数。否则,将执行静态字段初始值设定项 在第一次使用静态之前的实现相关时间 该班的领域。
答案 1 :(得分:3)
来自MSDN:
类的静态字段变量初始值设定项对应于a 以文本顺序执行的分配顺序 它们出现在课堂宣言中。
因此,请尝试将初始化移至static
构造函数之前,或在static
构造函数本身中包含关联。
即使你正在尝试一些不可能的事情,因为静态字段使用在静态构造函数内声明的变量。
试试这个:
private static AppSettingsSection _appSettingsLogsSection;
public static int LogSendIntervalMinutes;
static Configuration()
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
_appSettingsLogsSection = config.GetSectionGroup("Logs").Sections["appSettings"] as AppSettingsSection;
LogSendIntervalMinutes = Convert.ToInt32(_appSettingsLogsSection.Settings["LogSendIntervalMinutes"]); }
}
答案 2 :(得分:2)
使用ILSpy
或Reflector
查看编译代码,您将找到答案。
实际上 字段初始值设定项会在构造函数的实际代码 之前自动移到构造函数中。 (静态移动到静态的一个,实例转移到实例的构造函数)。
使用反射器反编译您的类的代码:
和实际的类结构如下所示:
此外,您可以看到编译器完成的优化,将构造函数中的两个单独行集成到单行中以初始化_appSettingsLogsSection。
答案 3 :(得分:1)
静态字段的初始化实际上是类型构造函数的一部分,并在调用自定义类型构造函数之前执行。因此,如果LogSendIntervalMinutes
是一个实例字段,则没有问题,但由于它是静态的,因此它的初始化在静态构造函数之前执行。您只需将LogSendIntervalMinutes
的初始化放在类型构造函数中。