当前位置: 首页 > 新闻动态 > 网络资讯

C# 静态构造函数方法 C#静态构造函数何时被调用

作者:星降 浏览: 发布日期:2026-02-03
[导读]:静态构造函数在类型首次被主动引用时执行且仅一次,触发场景包括访问静态成员、创建首个实例或反射触及类型元数据;typeof、数组长度获取及未赋值声明均不触发。
静态构造函数在类型首次被主动引用时执行且仅一次,触发场景包括访问静态成员、创建首个实例或反射触及类型元数据;typeof、数组长度获取及未赋值声明均不触发。

静态构造函数的触发时机

静态构造函数在类型首次被“主动引用”时执行,且仅执行一次。它不是在类定义时、也不是在第一次 new 实例时才触发——而是取决于 CLR 对该类型的首次“使用需求”。

常见触发场景包括:

  • 访问该类型的任意静态成员(static 字段、属性、方法)
  • 创建该类型的第一个实例(即 new

    MyClass()
  • 反射中调用 Type.GetMethod(...).Invoke(...) 等首次触及该类型元数据的操作(但仅当该操作导致类型初始化时)

注意:typeof(MyClass)MyClass[].Length(数组类型本身不触发)、或仅声明 MyClass obj;(未赋值)均不会触发静态构造函数。

为什么有时看起来没执行?

最常见原因是误判了“首次使用点”。比如下面这段代码:

class Program
{
    static void Main()
    {
        Console.WriteLine("Start");
        // 此处尚未访问 TestClass 的任何成员
        Console.WriteLine("End");
    }
}

class TestClass
{
    static TestClass()
    {
        Console.WriteLine("Static ctor fired!");
    }
}

输出只有 StartEnd——因为 TestClass 根本没被用到。CLR 不会为未引用的类型运行静态构造函数。

另一个典型陷阱是:在静态字段初始化器中引用了其他类,而那个类的静态构造函数又反过来依赖当前类——这会导致 TypeInitializationException,且异常堆栈里可能只显示“无法初始化类型”,不容易定位循环依赖。

与实例构造函数、static 字段初始化的顺序

静态构造函数的执行时机严格遵循以下顺序:

  • 所有 static 字段按声明顺序初始化(字面值或 = 表达式)
  • 然后才执行静态构造函数体(static TestClass() 中的代码)
  • 最后才是实例构造函数(每次 new 时)

例如:

class TestClass
{
    static int a = Console.WriteLine("a init") == 0 ? 1 : 0; // 先执行
    static TestClass()
    {
        Console.WriteLine("static ctor"); // 后执行
    }
}

输出一定是:a initstatic ctor。如果字段初始化表达式里抛出异常,静态构造函数根本不会进入。

不能显式调用,也不能带参数或访问修饰符

静态构造函数语法受限极严:

  • 不能加 public/private 等修饰符(编译报错 CS0515)
  • 不能有参数(否则编译报错 CS0137)
  • 不能被手动调用(如 TestClass.ctor() 是非法语法)
  • 不能被继承或重写(子类有自己独立的静态构造函数)

如果你需要“可控的静态初始化”,得改用显式方法 + 静态布尔标记,例如:

class TestClass
{
    private static bool _initialized;
    private static readonly object _lock = new object();

    public static void EnsureInitialized()
    {
        if (!_initialized)
        {
            lock (_lock)
            {
                if (!_initialized)
                {
                    // 手动初始化逻辑
                    _initialized = true;
                }
            }
        }
    }
}

这种模式绕过了 CLR 的自动触发机制,适合需要延迟、条件化或可重入初始化的场景。

真正容易被忽略的是:静态构造函数的线程安全性由 CLR 保证(自动加锁),但它的执行时机不可控——一旦类型被 JIT 或反射提前加载,就可能在你完全没预料的上下文里跑起来,比如在某个后台线程、甚至 ASP.NET Core 请求管道早期阶段。调试时看不到调用栈,只能靠日志或断点确认是否已触发。

免责声明:转载请注明出处:http://m.lexweb.cn/news/797431.html

扫一扫高效沟通

多一份参考总有益处

免费领取网站策划SEO优化策划方案

请填写下方表单,我们会尽快与您联系
感谢您的咨询,我们会尽快给您回复!