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
等一起使用,否则会看到一个类似下面这样的一个错误
file
是一个类型修饰符,只能用于类型,方法、属性等成员不能使用,也会报错
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
文件中,就会报错,如下所示
那么它是怎么实现的呢,我们可以反编译一下我们生成的 dll,我们可以找到有一个类型和我们定义的 FileLocalTypeSample2
是一样的,反编译结果如下
可以看到,我们用 file
声明的名称其实变掉了,实际的类型修饰符是 internal
的,这也意味着我们是有机会来访问到这个类型的,那我们就来试一下
首先直接引用这个类型,编译器会报错,类型不存在
既然不能直接访问,那我们来尝试一下反射吧,从下图可以看到我们成功通过反射获取到了这一类型
接着我们可以创建一个实例来试试
可以看到我们成功的创建的一个实例,并获取了其中 Age
属性的值
More
从上面的示例,我们可以看得出来, file
关键词是一个在编译器层面实现的特性,本质是由编译器生成了一个 internal
的类型再加一些编译检查来限制只能在声明的文件中进行访问,前面虽然我们通过反射的方式创建了file
修饰的类型,但是并不推荐这样做,随着编译器的更新生成的规则一旦变化就可能会 break
有一些不想不暴露出去的类型之前可能是声明一个 private
的类型,有了这个特性之后就可以多一种选择了~~
References
https://github.com/dotnet/csharplang/issues/6011
https://github.com/dotnet/csharplang/blob/main/proposals/file-local-types.md
https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp11Sample/FileLocalTypeSample.cs
https://github.com/WeihanLi/SamplesInPractice/blob/master/CSharp11Sample/FileLocalTypeSample2.cs