file-local 类型在 C# 12 中才正式支持
你无法在 C# 12 之前使用
file访问修饰符声明类型。如果编译器报错
error CS8904: Feature 'file-scoped type' is not available in C# 11. Please use language version 12 or greater,说明项目语言版本太低。必须显式升级到 C# 12 或更高版本——仅安装新 SDK 不够,还需在
.csproj中指定:
<LangVersion>12.0</LangVersion>或设为
latest。
用 file class
声明文件内私有类型
语法很简单:把
file关键字放在
class(或
struct、
interface、
delegate)前即可。它不接受其他访问修饰符(如
public、
internal),也不允许被继承或实现(除非在同一文件中)。
常见误用点:
试图在另一文件中new这个类型 → 编译失败,提示
The type 'X' is not accessible due to its protection level在同文件中写
public class A : file class B→ 允许;但跨文件继承
B→ 不允许,报
error CS0260: Missing partial modifier on declaration of 'B'; another partial declaration of this type exists(实际是语义错误,编译器用 partial 错误误导你) 声明
file interface I后,在另一文件中写
class C : I→ 编译失败,接口不可见
和 internal
+ 文件命名空间的差异
file类型比
internal更严格:后者在同一程序集任意文件都可见;前者只在声明它的 .cs 文件内有效,哪怕两文件共享同一根命名空间也互不可见。
性能与生成无区别——编译后仍是常规 IL 类型,只是元数据中
IsVisible为
false,且 C# 编译器在语义分析阶段就拦截了跨文件引用。
适用场景包括:
封装仅用于当前文件内某组方法的辅助类(比如 JSON 转换时的临时 DTO) 避免污染命名空间:不用再起类似MyService_TempHelper这种丑名字 替代局部函数无法承载的复杂逻辑(局部函数不能有字段、不能实现接口、不能被反射获取)
file-local 类型不能被反射跨文件发现
即使你用
Assembly.GetExecutingAssembly().GetTypes(),也不会包含其他文件里的
file类型——它们根本不在该程序集的公开类型列表中。但同一文件内的代码仍可通过
typeof(MyFileLocalClass)获取
Type对象。
注意一个边界情况:若在文件 A 中定义
file class AHelper,又在文件 A 中用
typeof(AHelper).Assembly.GetTypes(),返回数组里**不会**包含
AHelper—— 因为
GetTypes()只返回
IsVisible == true的类型,而
file类型总是
IsVisible == false。
所以别指望靠反射“绕过”作用域限制;这是编译期强制约束,不是运行时封装。
