10分钟内理解C# 10和.NET 6中的全局Usings
[[academy-video-youtube({"vid": "RWYrafpP53A", "start_time": "0", "title": "C# 10 和 .NET 6 的全局使用 10 分钟内完成", "creator": "Tim Corey", "length": "5m 33s"})]]
任何滚动过C#文件顶部的人都知道程序的规矩:在每个类声明上方排成一列的using语句,从一个文件重复到下一个文件。 一个典型的项目反复调用相同少量的命名空间,当需要更改时编辑所有这些命名空间是一项没有实际回报的工作。 C# 10新增了全局using指令来移除整个项目范围的重复。
在他的视频"C# 10的全局Using和.NET 6在10分钟内或更少中,Tim Corey解释了全局using的作用,放在什么地方以便团队能找到它们,以及允许您从成员调用中删除类前缀的静态变体。 他还指出需要注意的设计缺陷:全局导入命名空间会将整个项目暴露给该命名空间中的所有名称。 任何将相同五行using复制到每个新类中的人都将在这里找到清理方案。
重复问题
[0:17 - 1:50] Tim 从一个全新的.NET 6控制台应用程序开始,并创建一个包含PersonModel类的数据文件夹。 在Program.cs中引用该类需要在文件顶部添加预期的PersonModel意味着在该文件顶部也要添加相同的using行。 对于半打类来说,同样的导入被写了半打次。
这正是为global using设计的情况。 整个项目依赖的任何命名空间、类型或静态类都可以声明一次,并且无需每个文件的重复声明,就可在每个文件中使用。
提升Using到全局范围
[1:50 - 2:24] 语法是在现有指令前添加一个关键字:
global using GlobalUsings.Data;global using GlobalUsings.Data;那一行代码,放置在项目中的任何.cs文件中,使GlobalUsings.Data在同一个项目的每个其他文件中可用。 之前需要为PersonModel添加自己using行的其他类现在不再需要它; 类型自动解析。 范围在项目边界处停止,因此从兄弟项目引用的类仍需要正常的项目引用以及自己的全局或每文件using。
这并不会隐藏类型来自何处。 编译器仍然将PersonModel解析到其命名空间; 命名空间只是被预先导入。 运行时的行为与在每个文件顶部编写相同的using完全相同。
将Using集中在一个文件中
[2:24 - 3:32] 在随机文件中散布全局using指令在技术上是有效的,但在操作上是凌乱的。 如果一个新加入的团队成员看到PersonModel在没有明显导入的情况下解析,他们必须grep项目以找到它是如何全局化的。 现行的惯例是将所有全局using保存在项目根目录的一个文件中,命名为Usings.cs或GlobalUsings.cs等可预测的名称:
// Usings.cs at the project root
global using GlobalUsings.Data;
global using System.Text.Json;
global using System.Collections.Concurrent;// Usings.cs at the project root
global using GlobalUsings.Data;
global using System.Text.Json;
global using System.Collections.Concurrent;文件中不包含其他内容。 加入项目的任何人都只需知道唯一需要查看它的地方可以看到哪些是全局可用的。 这与文件范围的命名空间和其他礼节修剪功能相一致,这些功能在最近的C#版本中推出,都是为了使项目样板更易于一目了然。
全局Using静态方法导入
[3:32 - 4:50] 全局using指令与早期添加的using静态形式组合在一起 组合允许在整个项目中从静态类成员中删除类前缀。 Tim展示的驱动案例是Console.WriteLine:
global using static System.Console;global using static System.Console;在集中化的usings文件中使用这一单行,WriteLine("hello")。 同样的模式适用于数学助手(全局使用static System.Math让你可以不加前缀地写Sqrt(x))以及其他代码库中依赖很重的静态类。
这是Tim最小心的形式。 当方法很明显时,删除类前缀是一种可读性提升,但是当两个静态类暴露同名方法时,这可能会成为混淆的来源。 查看裸WriteLine调用的读者必须信任中央文件,而不是在上下文中看到源代码。
当全局导入相互干扰时
[4:50 - 5:14] 命名空间的目的是防止具有相同短名称的类型碰撞。 全局导入命名空间一次性移除了整个项目的缓冲区。 如果您的System.Data,现在每个文件都必须进行消歧。 代价不在于冲突发生的位置,而在于任何未来介于两者之间夹在一起的文件。
Tim的指导是有意地使用全局usings,优先考虑您知道项目普遍依赖的命名空间,并对全局using static特别小心。 一个合理的起始集是每个文件无论如何都会导入的命名空间; 超过此列表需要代码审查。
总结:减少礼节,但是行为相同
[5:14 - 5:33] 全局usings是一项旨在整个项目生命周期中带来收益的小功能。 每个不再携带多余导入行数的文件就是一个更快打开实际代码的文件,对共享命名空间的编辑在一个地方而不是多个地方进行。 同样,投入到类型别名和更广泛的using家族的相同用心也适用于这里:在可读性提升明确的地方使用它,并保持中央文件足够小,以便下一个开发人员可以一目了然地浏览。
结论
[5:14 - 5:33] 全局usings用项目范围的指令取代每个文件使用行,全局using static变体从静态成员调用中删除类前缀,项目根目录单个Usings.cs文件是保持其可发现性的惯例。 该特性是可选择和附加的,因此在现有代码库上采纳它是增量的。
示例提示:当您通过System.Collections.Generic),无需您编写它们。 将其与您自己的Usings.cs结合使用以进行项目特定的导入,每个文件的顶部会明显变短。

