C# 当类具有静态构造函数时,静态字段稍后初始化
通过运行以下简单代码:C# 当类具有静态构造函数时,静态字段稍后初始化,c#,.net,static,clr,coreclr,C#,.net,Static,Clr,Coreclr,通过运行以下简单代码: class Program { class MyClassWithStatic { public static int Number = SomeService.GetData(); static MyClassWithStatic() { Console.WriteLine("static ctor runs"); } } class SomeSe
class Program
{
class MyClassWithStatic
{
public static int Number = SomeService.GetData();
static MyClassWithStatic()
{
Console.WriteLine("static ctor runs");
}
}
class SomeService
{
public static int GetData()
{
Console.WriteLine("GetDataRuns");
return 42;
}
}
static void Main(string[] args)
{
InitService();
var value = MyClassWithStatic.Number;
Console.WriteLine(value);
}
private static void InitService()
{
Console.WriteLine("InitServiceRuns");
}
}
我的机器上的输出如下:
InitServiceRunsGetDataRuns
静态ctor运行
42
这意味着首先调用InitService方法,然后初始化MyClassWithStatic的静态字段,然后调用静态构造函数(事实上,通过在ILSpy和IlDasm中查看这一点,我们可以看到静态字段的初始化发生在cctor的开头) 在这一点上没有什么有趣的,一切都有意义,但是当我移除MyClassWithStatic的静态构造函数时(MyClassWithStatic变成了这个,其他一切都保持原样) 输出如下: GetDataRuns
InitServiceRuns
42
这意味着,通过删除静态构造函数,静态字段会更早初始化。由于初始化是静态构造函数的一部分(我通过ildasm研究它来说明这一点),其效果基本上是在前面调用静态构造函数 那么问题来了:
(还有问题nr3:)那么,我所描述的整个事情不是有点问题吗?带有静态构造函数的类将不会被标记为
beforefieldinit
标志,这允许运行时稍后对其进行初始化(换句话说,MyClassWithStatic.Number
将在您首次引用/访问MyClassWithStatic
时初始化)
获取更多信息,请访问
有人能解释这种行为吗?原因是什么
@JonSkeet在中有一段关于静态字段和静态构造函数的内容。下面是一个片段:
C#规范规定:
- 类的静态构造函数在给定时间内最多执行一次
应用程序域。触发静态构造函数的执行
在应用程序中发生以下事件中的第一个
域:
- 将创建该类的一个实例
- 函数的任何静态成员 类被引用
- 如果标记为BeforeFieldInit,则类型的初始值设定项方法为 在首次访问任何静态字段时或之前执行 为该类型定义的
- 如果未标记为BeforeFieldInit,则该类型为 初始化器方法被执行((在(即,由)触发):首先 访问该类型的任何静态或实例字段,或 调用该类型的任何静态、实例或虚拟方法))
beforefieldinit
标志时,运行时可能会在任意时间调用它,因为它在第一次访问任何定义的静态字段之前,这正是您所看到的
当静态构造函数
叫什么名字
唯一的事情就是在你的类型上创建一个静态类型构造函数。否则,你无法控制它的调用
那么,我描述的整个事情不是有点问题吗
在哪些方面存在问题?只要您知道自己的目的,我就看不出有问题。CLI规范明确说明了使用类型初始值设定项和不使用类型初始值设定项的保证。因此,如果您遵循这些指导原则,就不会有歧义。听起来像。您能描述一下为什么要控制它吗问题在第一个答案中得到了很好的解释,但在哪个方向上需要答案或解决方法?需要什么行为以及可以更改哪些类?实际上,情况是该类只有静态字段(=我的第二个示例)当一个探查器连接到它时,字段会在前面初始化。现在我不知道beforefieldinit标志,所以我尝试添加/删除一个cctor。我不想改变任何东西…我只是想了解原因。所以我们可以告诉你,如果一个类型被标记为beforefieldinit,那么连接一个探查器似乎很难ke a difference(与文档完全同步…)太好了,谢谢!正如您在我的案例中看到的我的评论,该类被标记为beforefieldinit…您知道在这种情况下,如果我附加一个探查器,初始化是否会更早发生吗?(因为这仍然与文档同步)基本上,在理解了这个案例之后,我的第二个问题变成了:“有什么可以改变w
class MyClassWithStatic
{
public static int Number = SomeService.GetData();
}