C# 11预览:通用数学、必要成员等

124 阅读5分钟

C# 11已经接近完成。这篇文章涵盖了17.3中的新功能,或者在我们4月份关于Visual Studio 17.2的更新2月份关于Visual Studio 17.1的更新中没有涉及的功能。

本预览中的新功能遵循C# 11的三个投资主题。

  • 对象初始化的改进。你可以在你的类型中更容易地支持构造器和对象初始化器,与你想为可变和不可变成员执行的规则无关。功能包括。
    • 必要的成员
    • ref 领域
  • 通用的数学支持。你可以为多种数字类型编写一次算法。这些功能使C#和.NET更容易被用于统计、机器学习和其他数学密集型的应用。特点包括:。
    • 接口中的静态抽象和静态虚拟成员
    • 放宽的右移要求
    • 无符号右移操作符
    • NumericIntPtr]
  • 开发者的生产力。我们增加了更多的语言功能,使你的工作效率更高。扩展的nameof 范围功能是新的。

改进对象初始化

必需成员让你可以编写要求调用者设置某些属性的类和结构类型。 考虑一下这个Person 类型。

public class Person
{
    public string FirstName { get; init; }
    public string LastName {get; init; }
}

调用者应该使用对象初始化器来设置FirstNameLastName 属性的值。但是在17.3之前,编译器不能强制要求调用者必须设置这些属性。一个需要参数的构造函数是确保用户设置FirstNameLastName 属性的唯一方法。要求成员向编译器和调用者传达他们必须设置这些属性。在成员声明中添加required 修改器。

public class Person
{
    public required string FirstName { get; init; }
    public required string LastName {get; init; }
}

所有调用者必须包括FirstNameLastName 属性的对象初始化器,否则编译器会发出错误。编译器会通知调用者,所需的成员没有被初始化。开发者必须立即解决这个问题。

如果Person 类型是为早期版本编写的,并且包括一个设置属性的构造函数,你仍然可以使用必要的成员。你应该用SetsRequiredMembers 属性来注释任何现有的构造函数。

public class Person
{
    public required string FirstName { get; init; }
    public required string LastName {get; init; }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }

    public Person() {}
}

SetsRequiredMembers 属性表明构造函数设置了所有必需的成员。编译器知道使用Person(string firstName, string lastName) 构造函数的调用者已经设置了所需成员。无参数构造函数不包括该属性,所以使用该构造函数的调用者必须使用对象初始化器初始化所有需要的成员。

上面的例子使用了属性,但你也可以将所需成员应用到字段声明中。

这个预览版还包含了对ref 字段和scoped 值的初始实现。这些变化为ref struct 类型中的ref 字段提供了能力。你也可以使用scoped 关键字来限制ref 参数的生命周期。该功能建议和更新的变化提供了目前关于该功能的最佳文档。我们发现了一些需要改变语言才能安全使用的场景。更新的变化将在以后的预览中提供,文档将反映最终的设计。

通用数学支持

我们增加了激励场景为通用数学的功能。你只有在高级场景中才会直接使用这些功能,例如编写在多种数字类型上工作的数学算法。否则,你会间接受益,因为运行时使用这些功能。

在接口中增加静态抽象和虚拟成员,为通用数学提供了许多重要的基础设施。这个功能允许接口声明运算符或其他静态方法。实现接口的类必须提供static abstract 方法的实现,就像接口中声明的其他方法一样。编译器会在编译时解决对static 方法的调用,包括运算符。没有像实例方法那样的运行时调度机制。文档中提供了更多关于使这一特性发挥作用所需的特定语言规则的细节。

其他的语言特性平滑了数字类型的一些差异,使其更容易编写通用数学算法。右移运算符不再要求第二个操作数是int 。任何积分类型都可以。nintnuint 类型分别是System.IntPtrSystem.UIntPtr 的同义词。这些关键字可以用来代替这些类型。事实上,新的分析器会温柔地提示你,让你更喜欢关键字而不是类型名称。最后,当你执行无符号移位时,无符号右移操作符 (>>>) 避免了转换。

结合起来,这些变化和其他变化,如检查过的运算符,支持通用数学运行时的变化。语言的改进意味着运行时团队可以在.NET的所有数字类型中提供改进。当你的类型使用运算符或其他静态方法实现合约时,你也可以利用这些功能。

开发者的生产力

nameof 操作符现在可以与方法参数一起使用。这个功能使你能够在方法的属性声明中使用nameof 操作符,就像下面的例子所示。

[return: NotNullIfNotNull(nameof(url))]
string? GetTopLevelDomainFromFullUrl(string? url)

试一试吧

请下载最新的Visual Studio 2022预览版并安装.NET 7预览版,或者你可以单独安装.NET 7的最新预览版。Preview一旦你安装了它,你就可以通过创建或打开一个C#项目并将LangVersion ,来尝试新的功能。

这个Visual Studio预览版使我们更接近于C# 11的完整功能集。在这个版本中,我们继续在多个主题上进行投资。根据你已经给我们的反馈,我们一路走来进行了修正。现在是下载预览版的好时机,尝试所有的新功能,并给我们反馈。我们正在倾听并为C# 11和.NET 7做最后的更新。