一探即将到来的 C# 10

前言本来因为懒不想写这篇文章 , 但是不少人表示有兴趣 , 于是最后决定还是写一下 。
.NET 6 最近几个预览版一直都在开发体验(如 hot reload、linker 等)、平台支持(如 Android、IOS 等)、工具链(如 crossgen2、PGO 工具和 wasm 的 AOT 等)、JIT(如 LSRA、Jump threading、PGO 和 guarded devirtualization 以及使 struct 保持在寄存器上等)、GC(如 Regions 等)以及 BCL(如 TimeOnly、DateOnly 以及 Json DOM 等)方面做改进 , 然而却一直没有公布 C# 10 的任何内容 , 即使在 Build 2021 大会上也没有提及这方面内容 。然而实际上不少特性的实现已经接近尾声了 , 那么让我们提前来看看 C# 10 可以为我们带来什么东西 。
当然 , 不是所有下面列出的特性都会一定进入 C# 10 , 也可能会和本文有所出入 , 我在每一个特性后面加了一个百分比表示最终实装的可能性 , 仅供参考 。
Backing Fields(60%)
相信不少人在编写属性的时候 , 总是想“如果能不用手动写字段的定义就好了” , 现在这个梦想成真了:
private int myInt;public int MyInt { get => myInt; set => myInt = value; }C# 10 中新增了一个 field , 当使用它时会自动为属性创建字段定义 , 不需要再手动定义字段了 。
public int MyInt { get => field; set => field = value; }Record Structs(100%)
Records 此前只支持 class , 但是现在同样支持 struct 啦 , 于是你可以定义值类型的 record , 避免不必要的堆内存分配:
【一探即将到来的 C# 10】record struct Point(int X, int Y);with on Anonymous Objects(80%)
此前 with 只能配合 records 使用 , 但是现在它被扩展到了匿名对象上 , 你可以通过 with 来创建匿名对象的副本并且修改它的值啦:
var foo = new { A = 1, B = "test", C = 4.4 };var bar = foo with { A = 3 };Console.WriteLine((bar.A, bar.B, bar.C)); // (3, test, 4.4)Global Usings(80%)
此前 using 语句的生效范围是单个文件的 , 如果你想使用一些 namespace , 或者定义一系列的类型别名在整个项目内使用 , 那么你就需要这样:
using System.Linq;using static System.Math;using i32 = System.Int32;using i64 = System.Int64;然后在每个文件中重复一遍 。但是现在不需要了 , 你可以定义全局的 using 了:
global using System.Linq;global using static System.Math;global using i32 = System.Int32;global using i64 = System.Int64;然后在整个项目中就都可以用了 。
File Scoped Namespace(90%)
C# 10 开始你将能够在文件顶部指定该文件的 namespace , 而不需要写一个 namespace 然后把其他代码都嵌套在大括号里面 , 毕竟绝大多数情况下 , 我们在写代码时一个文件里确实只会写一个 namespace , 这样可以减少一层嵌套也是很不错的:
namespace MyProject;class MyClass{// ...}如果采用这样的写法 , 每一个文件将只能声明一个 namespace 。
Constant Interpolated String(100%)
顾名思义 , 常量字符串插值:
const string a = "foo";const string b = $"{a}_bar"; // foo_bar常量字符串插值将在编译时完成 。
Lambda Improvements(100%)
C# 10 大幅度改进了 lambda , 扩展了使用场景 , 并改进了一系列的推导 , 提出自然委托类型 , 还函数上升至 first-class 。
支持 Attributes
f = [Foo] (x) => x; // 给 lambda 设置f = [return: Foo] (x) => x; // 给 lambda 返回值设置f = ([Foo] x) => x; // 给 lambda 参数设置支持显示指定返回值类型
此前 C# 的 lambda 返回值类型靠推导 , C# 10 开始允许在参数列表最前面显示指定 lambda 类型了:
f = int () => 4;支持 ref 等修饰
f = ref int (ref int x) => ref x; // 返回一个参数的引用First-class Functions
方法可以被隐式转换到 Delegate , 使得函数上升至 first-class 。
Delegate f = 1.GetHashCode; // Func<int>object g = 2.ToString; // object(Func<string>)var s = (int x) => x; // Func<int, int>将函数作为变量 , 然后传给另一个函数的参数:
void Foo(Func<int> f){Console.WriteLine(f());}int Bar(){return 5;}var baz = Bar;Foo(baz);


推荐阅读