4

C# 11正式发布 | 程序师 - 程序员、编程语言、软件开发、编程技术

 1 year ago
source link: https://www.techug.com/post/csharp-11-release/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

C# 11正式发布



出品 | OSC开源社区(ID:oschina2013)

C# 11 现已发布。公告称,“随着每个版本的发布,社区的参与度越来越高,贡献了从建议、见解和错误报告到整个功能实现的所有内容。这真的是每个人的 C#。”

新版本中的一些亮点更新内容包括:

UTF-8 字符串(UTF-8 String Literals)

默认情况下,C# 字符串被硬编码为 UTF-16,而 Internet 上通行的字符串编码是 UTF-8。为了最大限度地减少转换的麻烦和性能开销,现在可以简单地为你的 string literals 附加一个u8后缀,以便立即将它们转换为 UTF-8:

var u8 = "This is a UTF-8 string!"u8;

UTF-8 string literals 只是给你返回一个字节块 —— 以ReadOnlySpan<byte>形式。对于那些需要 UTF-8 编码的场景,这可能比一些专门的新的 UTF-8 字符串类型更有用。

阅读有关 UTF-8 字符串文字的文档:https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/reference-types#utf-8-string-literals

原始字符串 (Raw string literals)

从 C# 11 开始,可以使用原始字符串字面量更轻松地创建多行字符串,或使用需要转义序列的任何字符。原始字符串字面量无需使用转义序列。你可以编写字符串,包括空格格式,以及你希望在输出中显示该字符串的方式。 原始字符串字面量:

  • 以至少三个双引号字符序列 (""") 开头和结尾。可以使用三个以上的连续字符开始和结束序列,以支持包含三个(或更多)重复引号字符的字符串字面量。

  • 单行原始字符串字面量需要左引号和右引号字符位于同一行上。

  • 多行原始字符串字面量需要左引号和右引号字符位于各自的行上。

  • 在多行原始字符串字面量中,会删除右引号左侧的任何空格。

Raw string literals 由至少三个双引号分隔:

var raw1 = """This\is\all "content"!""";
Console.WriteLine(raw1);

This prints:

This\is\all "content"!

如果你需要三个或更多的"s 成为你内容的一部分,只需在外部使用更多的"s。开头和结尾必须一致。

var raw2 = """""I can do ", "", """ or even """" double quotes!""""";

这使得粘贴、维护和一目了然地阅读文字所包含的内容变得非常容易。

多行 raw string literals 也可以截断前导空格:末端引号的位置决定了空格开始包含在输出中的位置:

var raw3 = """
<element attr="content">
<body>
This line is indented by 4 spaces.
</body>
</element>
""";
// ^white space left of here is removed

由于末端引号的左侧有四个空格,因此将从每行内容的开头删除四个空格,从而产生以下输出:

<elementattr="content">
<body>
This line is indented by 4 spaces.
</body>
</element>

此外,Raw string literals 还支持插值,可在文档中阅读有关的更多信息:https://learn.microsoft.com/dotnet/csharp/programming-guide/strings/#raw-string-literals

对静态成员进行抽象

在 C# 11 中发布了对接口中静态虚拟成员的支持,此功能在 C# 10 中处于预览状态。有了它,你现在可以定义一个非常简单的数学接口:

publicinterfaceIMonoid<TSelf> whereTSelf: IMonoid<TSelf>
{
publicstaticabstractTSelfoperator+(TSelf a, TSelf b);
publicstaticabstractTSelfZero{ get; }
}

任何人现在都可以通过为两个静态成员提供实现并将自己作为TSelf类型参数传递来实现此接口:

publicstructMyInt: IMonoid<MyInt>
{
intvalue;
publicMyInt(int i) => value= i;
publicstaticMyIntoperator+(MyInt a, MyInt b) => newMyInt(a.value+ b.value);
publicstaticMyIntZero=> newMyInt(0);
}

重要的是,你如何使用这些抽象的操作?当没有实例可供调用时,你如何调用虚拟成员?答案是通过泛型:

T AddAll<T>(params T[] elements) where T : IMonoid<T>
{
T result = T.Zero;
foreach(var element in elements)
{
result += element;
}
return result;
}

类型参数TIMonoid<T>接口约束,这使得该接口的静态虚拟成员Zero+可以在Titself 上被调用。

现在我们可以用一些MyInt来调用泛型方法,而+Zero的正确实现则通过类型参数传递进来:

MyInt sum = AddAll<MyInt>(newMyInt(3), newMyInt(4), newMyInt(5));

事实上,.NET 7 提供了一个新的命名空间 System.Numerics,其中充满了数学接口,代表了不同的运算符组合和其他你想使用的静态成员:上述小 IMonoid<T> 接口的 “grown-up” 版本。.NET 中的所有数字类型现在都实现了这些新的接口 — 你也可以为你自己的类型添加这些接口。

还值得注意的是,静态虚拟成员对数学以外的其他事物也很有用。更多详情可在有关静态抽象接口方法和通用数学的文档中查看。即使你不使用静态虚拟成员创建接口,也可以从他们现在和将来对 .NET 库所做的改进中受益。

列表模式(List patterns)

Pattern matching 是在 C# 7 中引入的,从那时起它已发展成为该语言中最重要和最强大的控制结构之一;C# 11 添加了列表模式从 C# 11 开始,可以将数组或列表与模式的序列进行匹配,如以下示例所示:

int[] numbers = { 1, 2, 3 };

Console.WriteLine(numbers is [1, 2, 3]); // True
Console.WriteLine(numbers is [1, 2, 4]); // False
Console.WriteLine(numbers is [1, 2, 3, 4]); // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // True

如前面的示例所示,当每个嵌套模式与输入序列的相应元素匹配时,列表模式就会匹配。可使用列表模式中的任何模式。若要匹配任何元素,请使用弃元模式,或者,如果还想捕获元素,请使用 var 模式,如以下示例所示:

List<int> numbers = new() { 1, 2, 3 };

if (numbers is [var first, _, _])
{
Console.WriteLine($"The first element of a three-item list is {first}.");
}
// Output:
// The first element of a three-item list is 1.

前面的示例将整个输入序列与列表模式匹配。若要仅匹配输入序列开头或 / 和结尾的元素,请使用列表模式中的切片模式..,如以下示例所示:

Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]);  // True
Console.WriteLine(new[] { 1, 1 } is [_, _, ..]); // True
Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]); // False
Console.WriteLine(new[] { 1 } is [1, 2, ..]); // False

Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]); // True
Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]); // False
Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]); // True

Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]); // True
Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]); // True
Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]); // False

切片模式匹配零个或多个元素。最多可在列表模式中使用一个切片模式。

还可以在切片模式中嵌套子模式,如以下示例所示:

voidMatchMessage(string message)
{
var result = message is ['a' or 'A', .. var s, 'a' or 'A']
? $"Message {message} matches; inner part is {s}."
: $"Message {message} doesn't match.";
Console.WriteLine(result);
}

MatchMessage("aBBA"); // output: Message aBBA matches; inner part is BB.
MatchMessage("apron"); // output: Message apron doesn't match.

voidValidate(int[] numbers)
{
var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid";
Console.WriteLine(result);
}

Validate(new[] { -1, 0, 1 }); // output: not valid
Validate(new[] { -1, 0, 0, 1 }); // output: valid

本文文字及图片出自 OSC开源社区


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK