C# 11 中的 file local type

Intro

在之前的版本中,我们想要一个类型只在当前的类型中生效,通常我们会在一个类的内部声明一个 private 的类型以此来控制这个类型的访问权限,在 C# 11 中引入了一个 file local type,仅在声明类型的这个文件中可以访问,这样我们就可以不用声明成一个私有类型了,下面就来看个示例吧

Sample

C# 11 新增加了一个 file 关键词,这个关键词也属于访问修饰符的一种,用于限定类型只有当前文件有效,使用和其他访问修饰符类似,使用示例如下:.

file class FileLocalTypeSample2
{
    public int Age { get; set; } = 10;
}

file 本身就是一个访问修饰符,所以它不能再与其他访问修饰符一起使用,比如说 public/internal/private 等一起使用,否则会看到一个类似下面这样的一个错误

C# 11 中的 file local type

file 是一个类型修饰符,只能用于类型,方法、属性等成员不能使用,也会报错

C# 11 中的 file local type

file 不限于 class 也可以用于接口、结构体以及 C# 9/10 引入的 record

file class FileLocalTypeSample2
{
    public int Age { get; set; } = 10;
}

file record FileLocalRecord();

file struct FileLocalStruct
{
    public string RecordName => nameof(FileLocalRecord);
}

file record struct FileLocalRecordStruct { }

file interface IAnimal
{
    string Name => GetType().Name;
}

file class Cat : IAnimal { }

class Dog : IAnimal { }

当你尝试在另外一个文件中尝试访问 file 修饰的类型时,会访问不到,比如说上面定义的类型是在 FileLocalTypeSample2.cs 文件中,而下面尝试访问则是在 FileLocalTypeSample.cs 文件中,就会报错,如下所示

C# 11 中的 file local type

那么它是怎么实现的呢,我们可以反编译一下我们生成的 dll,我们可以找到有一个类型和我们定义的 FileLocalTypeSample2 是一样的,反编译结果如下

C# 11 中的 file local type

可以看到,我们用 file 声明的名称其实变掉了,实际的类型修饰符是 internal 的,这也意味着我们是有机会来访问到这个类型的,那我们就来试一下

首先直接引用这个类型,编译器会报错,类型不存在

C# 11 中的 file local type

既然不能直接访问,那我们来尝试一下反射吧,从下图可以看到我们成功通过反射获取到了这一类型

C# 11 中的 file local type

接着我们可以创建一个实例来试试

C# 11 中的 file local type

可以看到我们成功的创建的一个实例,并获取了其中 Age 属性的值

More

从上面的示例,我们可以看得出来, file 关键词是一个在编译器层面实现的特性,本质是由编译器生成了一个 internal的类型再加一些编译检查来限制只能在声明的文件中进行访问,前面虽然我们通过反射的方式创建了file 修饰的类型,但是并不推荐这样做,随着编译器的更新生成的规则一旦变化就可能会 break

有一些不想不暴露出去的类型之前可能是声明一个 private  的类型,有了这个特性之后就可以多一种选择了~~