宣布 C# 12 正式推出

C#12引入了包括集合表达式、主构造函数优化、别名语法和默认参数在内的新功能,旨在提高代码简洁性和执行速度。同时,.NET8和VisualStudio工具也进行了更新。文章还讨论了实验性特性如实验属性和拦截器,尽管后者处于预览阶段。
摘要由CSDN通过智能技术生成

C# 12 现已推出!您可以通过下载.NET 8、最新的Visual StudioVisual Studio Code 的 C# Dev Kit来获取它。

对于现有项目,您还需要表明您想要更改语言版本。TargetFramework您可以通过更改为 .NET 8 来更改语言版本:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
...
    </PropertyGroup>
</Project>

C# 12 通过简化的语法和更快的执行速度提高了开发人员的工作效率。您可以在 MS Learn 上的C# 12 新增功能一文中查看每个功能的详细信息。新增功能一文包含指向 MS Learn 上反映新功能的 C# 文档更新的链接。

简化您的代码

C# 的每个版本都可以帮助您编写更好的代码 - 更简单的代码可以更好地表达您的意图。与您以前编写的代码相比,新方法的速度相同或更快,并且具有相同或更少的分配。您可以放心地采用这些新功能。新功能的设计目标之一是确保采用新功能不会降低性能。

C# 12 引入了集合表达式、所有类和结构的主构造函数、任何类型的别名语法以及可简化代码的 lambda 表达式的默认参数。

集合表达式

在 C# 12 之前,创建集合需要针对不同场景使用不同的语法。初始化List<int>所需的与int[]or不同的语法Span<int>。以下是创建集合的几种方法:

int[] x1 = new int[] { 1, 2, 3, 4 };
int[] x2 = Array.Empty<int>();
WriteByteArray(new[] { (byte)1, (byte)2, (byte)3 });
List<int> x4 = new() { 1, 2, 3, 4 };
Span<DateTime> dates = stackalloc DateTime[] { GetDate(0), GetDate(1) };
WriteByteSpan(stackalloc[] { (byte)1, (byte)2, (byte)3 });

集合表达式是统一的语法:

int[] x1 = [1, 2, 3, 4];
int[] x2 = [];
WriteByteArray([1, 2, 3]);
List<int> x4 = [1, 2, 3, 4];
Span<DateTime> dates = [GetDate(0), GetDate(1)];
WriteByteSpan([1, 2, 3]);

您不仅可以使用单一语法,而且编译器可以为您创建快速代码。在许多情况下,编译器会设置收集容量并避免复制数据。

如果这还不够,您可以使用新的展开运算符在集合表达式中包含一个或多个集合或可枚举表达式的元素:

int[] numbers1 = [1, 2, 3];
int[] numbers2 = [4, 5, 6];
int[] moreNumbers = [.. numbers1, .. numbers2, 7, 8, 9];
// moreNumbers contains [1, 2, 3, 4, 5, 6, 7, 8, ,9];

任何扩展表达式的实现都经过优化,并且通常比您可能编写的用于组合集合的代码更好。

我们对集合表达式未来可能开展的工作的反馈非常感兴趣。var我们正在考虑扩展集合表达式,以在 C# 的未来版本中包含字典和对(自然类型)的支持。

与许多新的 C# 功能一样,分析器可以帮助您检查新功能并更新代码:

有关集合表达式的更多信息,请参阅MS Learn 上的这篇文章

任何类或结构上的主构造函数

C# 12 扩展了主构造函数以适用于所有类和结构,而不仅仅是记录。主构造函数允许您在声明类时定义构造函数参数:

public class BankAccount(string accountID, string owner)
{
    public string AccountID { get; } = accountID;
    public string Owner { get; } = owner;

    public override string ToString() => $"Account ID: {AccountID}, Owner: {Owner}";
}

主构造函数参数最常见的用途是:

  • 作为 base() 构造函数调用的参数。
  • 初始化成员字段或属性。
  • 在实例成员中引用构造函数参数。
  • 删除依赖注入中的样板。

您可以将主构造函数参数视为整个类声明范围内的参数。

您可以将主构造函数添加到任何类型:classstruct和。当在and类型上使用时,主构造函数参数位于整个or定义的范围内。您可以使用参数来初始化字段或属性,或者在其他成员的主体中。当用于类型时,编译器为每个主构造函数参数生成一个公共属性。这些属性只是为类型自动生成的众多成员之一。record classrecord structclassstructclassstructrecordrecord

我们对主要构造器未来可能的工作的反馈非常感兴趣。我们正在考虑允许您将主构造函数参数标记为 和 ,readonly以表明您想要创建一个公共属性。

在本文中了解有关主构造函数的更多信息。要更深入地了解对记录和非记录使用主构造函数,请查看教程:探索主构造函数

别名任意类型

别名类型是从代码中删除复杂类型签名的便捷方法。using从 C# 12 开始,其他类型在别名指令中有效。例如,这些别名在早期版本的 C# 中无效:

using intArray = int[]; // Array types.
using Point = (int x, int y);  // Tuple type
using unsafe ArrayPtr = int*;  // Pointer type (requires "unsafe")

您可以查看功能规范允许使用别名指令来引用带有指针和不安全类型的别名的任何类型。using

与其他using别名一样,这些类型可以在文件顶部和global using语句中使用。

在本文中了解有关别名任何类型的更多信息。

默认 lambda 参数

从 C# 12 开始,您可以在 lambda 表达式中声明默认参数:

var IncrementBy = (int source, int increment = 1) => source + increment;

Console.WriteLine(IncrementBy(5)); // 6
Console.WriteLine(IncrementBy(5, 2)); // 7

默认 lambda 参数允许调用代码跳过传递值,并允许您将参数添加到现有 lambda 表达式,而不会破坏调用代码。这简化了对 lambda 表达式的访问,就像方法中的默认参数简化了调用方法一样。

在本文中了解有关默认 lambda 参数的更多信息。

让你的代码更快

我们不断提高您使用原始内存的能力,以提高应用程序性能。

多年来我们在 C# 中所做的性能改进都很重要,无论您是否直接使用它们。大多数应用程序变得更快,因为 .NET 运行时和其他库利用了这些增强功能。当然,如果您的应用程序在热路径中使用内存缓冲区,您也可以利用这些功能。它们将使您的应用程序运行得更快。

在 C# 12 中,我们添加了ref readonly参数和内联数组。

ref 只读参数

参数的添加ref readonly提供了通过引用或通过值传递参数的最终组合。参数的参数ref readonly必须是变量。ref与和参数类似out,参数不应该是文字值或常量。文字参数会生成警告,并且编译器会创建一个临时变量。与参数一样inref readonly参数也无法修改。当方法ref readonly不会修改参数但需要其内存位置时,该方法应该声明参数。

在本文中了解有关参数的更多信息ref readonly

内联数组

内联数组提供了一种使用内存缓冲区的安全方法。内联数组是一种基于结构的固定长度数组类型。您已经能够使用存储或指针来操作内存块stackalloc。但这些技术要求您的程序集启用不安全的代码。当您的应用程序需要使用内存块来存储结构数组时,您现在可以声明内联数组类型。该类型表示一个固定大小的数组。您可以在安全代码中使用它们,并在操作缓冲区时提高应用程序的性能。

在本文中了解有关内联数组的更多信息。

帮助我们走得更快

有时,我们会向 C# 添加功能作为实验,或者为了提高 C# 或 .NET 的开发效率。C# 12 带来了其中两个功能:实验属性和拦截器。

实验属性

我们偶尔会将功能放入 .NET 或 C# 的发布版本中,因为我们需要反馈,或者功能无法在单个周期内完成。在这些情况下,我们想明确表示我们尚未承诺该功能或实施。我们添加了System.Diagnostics.CodeAnalysis.ExperimentalAttribute以便更好地阐明何时发生这种情况。

当代码使用实验性类型或成员时,将会发生错误,除非调用代码也被标记为实验性。每次使用都ExperimentalAttribute包含一个诊断 ID,它允许您通过显式编译器选项或 #pragma 抑制各个实验功能的错误,以便您可以探索实验功能。

类型、成员和程序集可以用 进行标记ExperimentalAttribute。如果某个类型被标记为实验性的,则其所有成员都被视为实验性的。如果程序集或模块被标记为实验性的,则其中的所有类型都被标记为实验性的。

我们强烈建议依赖于具有属性的任何内容的库作者Experimental也将使用该属性的所有代码标记为ExperimentalAttribute. 如果库作者在其库中有实验性功能,我们也鼓励他们使用ExperimentalAttribute

在本文中了解有关实验属性的更多信息。

拦截器

拦截器是一项实验性功能,可在 C# 12 的预览模式下使用。该功能可能会在未来版本中进行重大更改或删除。因此,不建议用于生产或发布的应用程序。如果您使用拦截器,请使用ExperimentalAttribute.

拦截器允许方法调用重定向。例如,这将允许为特定参数生成的方法的优化版本来替换效率较低的通用方法。

如果您有兴趣,可以通过阅读拦截器功能规范来了解有关拦截器的更多信息。

下一步

C# 12 只是令人兴奋的 .NET 8 版本的一部分。您可以在.NET 8 博客文章中了解其他功能。

下载.NET 8Visual Studio 2022 17.8并查看 C# 12!

文章作者 | Kathleen Dollard(凯瑟琳·多拉德)

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值