C# 10 中的新增功能
C# 10 向 C# 语言添加了以下功能和增强功能:
- 记录结构
- 结构类型的改进
- 内插字符串处理程序
global using
指令- 文件范围的命名空间声明
- 扩展属性模式
- 对 Lambda 表达式的改进
- 可使用
const
内插字符串 - 记录类型可密封
ToString()
- 改进型明确赋值
- 在同一析构中可同时进行赋值和声明
- 可在方法上使用
AsyncMethodBuilder
属性 - CallerArgumentExpression 属性
- 增强的
#line
pragma - 警告波 6
.NET 6 支持 C# 10。 有关详细信息,请参阅 C# 语言版本控制。
可以通过 .NET 下载页下载最新 6 .NET SDK。 还可以下载 Visual Studio 2022,其中包括 .NET 6 SDK。
注意
我们有兴趣了解你对这些功能的反馈。 如果发现这些新功能存在问题,请在 dotnet/roslyn 存储库中创建新问题。
记录结构
可以使用 record struct
或 readonly 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
方法。 sealed
ToString
确保了所有派生记录类型都使用某个通用基记录类型中定义的 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
语句中的 true
或 false
语句以及 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 的示例的功能规范。