C# 10 中的新增功能

C# 10 向 C# 语言添加了以下功能和增强功能:

.NET 6 支持 C# 10。 有关详细信息,请参阅 C# 语言版本控制

可以通过 .NET 下载页下载最新 6 .NET SDK。 还可以下载 Visual Studio 2022,其中包括 .NET 6 SDK。

注意

我们对你对这些功能的反馈感兴趣。 如果发现这些新功能存在问题,请在 dotnet/roslyn 存储库中创建新问题

记录结构

可以使用 record structreadonly record struct 声明声明值类型记录。 现在,你可以通过 record class 声明阐明 record 是引用类型。

结构类型的改进

C# 10 引入了与结构类型相关的以下改进:

  • 可以在结构类型中声明实例无参数构造函数,并在声明实例字段或属性时对它们进行初始化。 有关详细信息,请参阅结构类型一文的结构初始化和默认值部分。
  • with 表达式的左侧操作数可以是任何结构类型,也可以是匿名(引用)类型。

内插字符串处理程序

可以创建一种类型,该类型从内插字符串表达式生成结果字符串。 .NET 库在许多 API 中都使用此功能。 可以按照本教程生成一个内插字符串处理程序。

全局 using 指令

可将 global 修饰符添加到任何 using 指令,以指示编译器该指令适用于编译中的所有源文件。 这通常是项目中的所有源文件。

文件范围的命名空间声明

可使用 namespace 声明的新形式,声明所有后续声明都是已声明的命名空间的成员:

namespace MyNamespace;

这个新语法为 namespace 声明节省了水平和垂直空间。

扩展属性模式

从 C# 10 开始,可引用属性模式中嵌套的属性或字段。 例如,窗体的模式

{ Prop1.Prop2: pattern }

在 C# 10 及更高版本中有效,且其等效项

{ Prop1: { Prop2: pattern } }

在 C# 8.0 及更高版本中有效。

有关详细信息,请参阅扩展属性模式功能建议说明。 有关属性模式的详细信息,请参阅模式一文的属性模式部分。

Lambda 表达式改进

C# 10 包括了对 Lambda 表达式的处理方式的许多改进:

  • Lambda 表达式可以具有自然类型,这使编译器可从 Lambda 表达式或方法组推断委托类型。
  • 如果编译器无法推断返回类型,Lambda 表达式可以声明该类型。
  • 属性可应用于 Lambda 表达式。

这些功能使 Lambda 表达式更类似于方法和本地函数。 在不声明委托类型的变量的情况下,这些改进使得人们可以更容易使用 Lambda 表达式,并且它们可以与新的 ASP.NET Core 最小 API 更无缝地工作。

常数内插字符串

在 C# 10 中,如果所有占位符本身均为常量字符串,可以使用字符串内插来初始化 const 字符串。 在生成应用程序中使用的常量字符串时,字符串内插可以创建更多可读的常量字符串。 占位符表达式不能为数值常量,因为在运行时这些常量会转换为字符串。 当前区域性可能会影响其字符串表示形式。 有关详细信息,请参阅有关 const 表达式的语言参考信息。

记录类型可以密封 ToString

在 C# 10 中,在记录类型中重写 ToString 时可以添加 sealed 修饰符。 密封 ToString 方法可阻止编译器为任何派生的记录类型合成 ToString 方法。 sealedToString 确保了所有派生记录类型都使用某个通用基记录类型中定义的 ToString 方法。 若要详细了解此功能,请阅读有关记录的文章。

在同一析构中进行赋值和声明

此更改取消了早期 C# 版本中的限制。 以前,析构可以将所有值赋给现有变量,或将新声明的变量初始化:

// Initialization:
(int x, int y) = point;

// assignment:
int x1 = 0;
int y1 = 0;
(x1, y1) = point;

C# 10 取消了此限制:

int x = 0;
(x, int y) = point;

改进型明确赋值

在 C# 10 及更低版本中,在许多情况下,明确赋值和 Null 状态分析都会生成误报警告。 这些通常涉及与布尔常量的比较,仅在 if 语句中的 truefalse 语句以及 Null 合并表达式中使用变量。 这些示例会在早期版本的 C# 中生成警告,但在 C# 10 中不会:

string representation = "N/A";
if ((c != null && c.GetDependentValue(out object obj)) == true)
{
   representation = obj.ToString(); // undesired error
}

// Or, using ?.
if (c?.GetDependentValue(out object obj) == true)
{
   representation = obj.ToString(); // undesired error
}

// Or, using ??
if (c?.GetDependentValue(out object obj) ?? false)
{
   representation = obj.ToString(); // undesired error
}

此次改进的主要影响是,针对明确赋值和 Null 状态分析的警告更加准确。

允许在方法上使用 AsyncMethodBuilder 特性

在 C# 10 及更高版本中,除了可以为所有返回给定任务类型的方法指定方法生成器类型外,还可以为单个方法指定其他异步方法生成器。 自定义异步方法生成器可以实现高级的性能优化方案,其中给定的方法可受益于自定义生成器。

若要了解详细信息,请阅读有关编译器读取的属性的文章中有关 AsyncMethodBuilder 的部分。

CallerArgumentExpression 属性诊断

可以使用 System.Runtime.CompilerServices.CallerArgumentExpressionAttribute 来指定编译器用另一个实参的文本表示形式替换的形参。 此功能使库可以创建更具体的诊断。 以下代码测试条件。 如果条件为 false,则异常消息包含传递给 condition 的参数的文本表示形式:

public static void Validate(bool condition, [CallerArgumentExpression("condition")] string? message=null)
{
    if (!condition)
    {
        throw new InvalidOperationException($"Argument failed validation: <{message}>");
    }
}

可在语言参考部分的调用者信息属性一文中详细了解此功能。

增强型 #line pragma

C# 10 支持 #line pragma 的新格式。 你可能不会使用新格式,但你会看到它的作用。 这些增强功能支持使用 Razor 等域特定语言 (DSL) 实现更详细的输出。 Razor 引擎使用这些增强功能来改进调试体验。 你会发现调试器可以更准确地突出显示 Razor 源。 若要详细了解新语法,请参阅语言参考中有关预处理器指令的文章。 还可以阅读关于基于 Razor 的示例的功能规范