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

为何Roslyn编译器生成的C#本地函数IL访问修饰符是internal而非private

为什么Roslyn编译器生成的本地函数在IL中访问修饰符为internal而非private?

首先给出相关示例代码和生成的IL对照:
C# 示例代码:

private void M()
{
    bool f = true;
    bool x1() => f;
    static bool x2() => true;
}

对应生成的IL代码:

.method assembly hidebysig static
    bool '<M>g__x1|0_0' (
        valuetype C/'<>c__DisplayClass0_0'& ''
    ) cil managed { ... }

.method assembly hidebysig static
    bool '<M>g__x2|0_1' () cil managed { ... }

这个差异本质是C#语言层面的访问语义定义和编译器底层IL实现细节的区别,二者并不冲突,具体原因如下:

  • 微软官方文档提到的「本地函数是private的」是面向C#开发者的语义描述:它指的是本地函数仅在定义它的父方法内部可访问,C#编译器会在编译期强制校验这个规则,你既无法在父方法外调用本地函数,也不能主动给本地函数加private等访问修饰符,这个语义约束和IL层面的访问修饰符没有直接关系。
  • IL层面选择internal(对应IL的assembly标记)修饰符是出于实现层面的兼容性和性能考量:
    • 当本地函数捕获了父方法的变量时(比如示例中的x1),Roslyn会生成对应的闭包显示类(示例中的C/<>c__DisplayClass0_0)来存储捕获的变量。如果本地函数生成private修饰符,按照CLR的访问规则,只有它所属的类能访问该方法,同程序集的闭包显示类调用该方法时会触发额外的权限校验,增加不必要的运行时开销,使用internal可以直接避免这个问题。
    • 无论本地函数是否捕获变量、是否是静态本地函数,统一生成internal修饰符可以简化Roslyn的实现逻辑,不需要针对不同场景做分支处理,降低实现复杂度。
  • 这种实现完全不会破坏C#的访问约束:Roslyn生成的本地函数都会用<M>g__x1|0_0这类包含特殊字符的混淆命名,C#语法本身不允许用户声明或调用这类名称的方法,所以哪怕是internal修饰符,也不会出现用户代码意外访问到本地函数的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 22:45:05