You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#中类的静态构造函数(cctor)由谁调用?

关于C#静态构造函数(cctor)调用者的疑问

测试代码

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");
B b = new B();

public class A
{
    static A()
    {
        Console.WriteLine("Static ctor A");
    }
    public A()
    {
        Console.WriteLine("ctor A");
    }
}
public class B:A
{
    static B()
    {
        Console.WriteLine("Static ctor B");
    }
    public B()
    {
        Console.WriteLine("ctor B");
    }
}

程序输出

Static ctor B
Static ctor A
ctor A
ctor B

疑问与观察

我的问题是:谁调用了静态构造函数?搜索资料得到的答案是“系统(CLR)会在类的任何实例出现前调用静态构造函数”,但查看IL代码后仍找不到静态构造函数(称为cctor)的调用线索。

Main方法的IL代码

.method private hidebysig static 
    void '<Main>$' (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x2050
    // Header size: 12
    // Code size: 18 (0x12)
    .maxstack 1
    .entrypoint
    .locals init (
        [0] class B b
    )

    IL_0000: ldstr "Hello, World!"
    IL_0005: call void [System.Console]System.Console::WriteLine(string)
    IL_000a: nop
    IL_000b: newobj instance void B::.ctor()
    IL_0010: stloc.0
    IL_0011: ret
} // end of method Program::'<Main>$'

在Main()中调用了B::.ctor(),B::.ctor()中又调用了A::.ctor(),但我未发现任何cctor的调用。我最初猜测是在.locals init阶段调用,但测试后证明并非如此。之后我猜想可能是构造函数中的ldarg.0导致的:

B类实例构造函数的IL代码

.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Method begins at RVA 0x20a8
    // Header size: 1
    // Code size: 20 (0x14)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void A::.ctor()
    IL_0006: nop
    IL_0007: nop
    IL_0008: ldstr "ctor B"
    IL_000d: call void [System.Console]System.Console::WriteLine(string)
    IL_0012: nop
    IL_0013: ret
} // end of method B::.ctor

以上是B::.ctor方法,第一行是ldarg.0,据我所知ldarg.0指代“this”,这是否意味着已经存在类的实例?是否为了引用“this”,CLR才调用了静态构造函数?我想明确C#中到底是谁调用了cctor。


解答

静态构造函数(cctor)的调用是CLR运行时自动触发的行为,不会在编译生成的IL代码里显式出现调用指令。

当执行newobj instance void B::.ctor()这条IL指令时,CLR会在真正执行实例构造函数前完成以下步骤:

  1. 检查B类的静态构造函数是否已执行,若未执行则先调用B的cctor;
  2. 由于B继承自A,CLR会继续检查A的静态构造函数执行状态,未执行则调用A的cctor;
  3. 等所有依赖的静态构造函数执行完毕后,才会继续分配实例内存、执行实例构造函数的逻辑。

你看到的ldarg.0是实例构造函数中引用当前实例的指令,但这个实例是在newobj指令执行时才分配内存的——静态构造函数的执行早于实例内存分配,和ldarg.0没有直接关联。

IL代码里找不到cctor调用的原因,是因为这部分逻辑属于CLR的运行时管控范畴,不是编译阶段生成的代码,而是CLR在处理类的首次访问(包括创建实例、访问静态成员等场景)时自动插入的执行逻辑。


内容的提问来源于stack exchange,提问作者Eric Su

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 03:40:32