Skip to content

.NET Core 实战 [No.201~207] 元组

🏷️ 《.NET Core 实战》

元组(Tuple)类型很早就有了,但在低于 7.0 的版本中,只能通过 Item1Item2 这样的属性来访问,没有实际的语义。

7.0 开始元组增加了语义上的支持等功能,更加易于使用。实际上这里说的元组已经不是指之前的 Tuple 类型了,而是新增的 值元组 ValueTuple 类型。

先说一下旧的元组类型。 Tuple 可以通过 new 关键字 或者 Tuple.Create() 方法 创建,只能通过 Item* 属性获取元素值,而且是只读属性,无法修改。

csharp
var namelessLetters = new Tuple<string, string>("a", "b");
namelessLetters = Tuple.Create("a", "b");
Console.WriteLine($"Item1:{namelessLetters.Item1}, Item2:{namelessLetters.Item2}");

7.0 及之后的几个小版本中对元组添加了很多特性;

  • 7.0

    • 增加了语义上的支持(可以对元素命名)
    • 支持解构(Deconstruct
    • 解构时支持弃元(_
  • 7.1

    • 元素名支持推断
  • 7.3

    • 支持 ==!= 操作符

新的元组类型 ValueTuple 是值类型,不需要分配堆内存,效率优于 Tuple 。此外,ValueTuple 的元素初始化以后是可以修改的。

ValueTuple 也可以和 Tuple 类似使用 new 关键字 或 ValueTuple.Create() 方法 初始化。不过推荐使用 C# 新语法来初始化,语法上更简洁易懂。

csharp
var namelessLetters = ("a", "b");
namelessLetters.Item1 = "A";
Console.WriteLine($"Item1:{namelessLetters.Item1}, Item2:{namelessLetters.Item2}"); // Item1:A, Item2:b

ValueTuple 支持对元素命名,可以通过如下三种方式声明。

csharp
(string Alpha, string Beta) namedLetters = ("a", "b");
csharp
var namedLetters = (Alpha: "a", Beta: "b");

这第三种是通过 7.1 中新增的推断功能来实现的,需要将项目的语言版本指定为 7.1 或以上。

csharp
var Alpha = "a";
var Beta = "b";
var namedLetters = ( Alpha, Beta );

可以通过指定的元素名获取或修改元素值,同时也仍旧支持使用 Item* 的方式获取或修改元素值。

csharp
namedLetters.Alpha = "A";
Console.WriteLine($"Alpha:{namedLetters.Alpha}, Beta:{namedLetters.Beta}"); // Alpha:A, Beta:b
Console.WriteLine($"Item1:{namedLetters.Item1}, Item2:{namedLetters.Item2}"); // Item1:A, Item2:b

验证下上面定义的 namedLetters 变量的类型。

csharp
Console.WriteLine($"The type of namedLeeters:{namedLetters.GetType()}");
// The type of namedLeeters:System.ValueTuple`2[System.String,System.String]

ValueTuple 支持解构。解构之后,元组中的字段可以作为普通变量来使用。

csharp
(string alpha, string beta) = ("a", "b");
Console.WriteLine($"alpha:{alpha}, beta:{beta}"); // alpha:a, beta:b

解构更常用于的是解构方法返回值中的元组。

csharp
(string Alpha, string Beta) GetLetters()
{
    return ("a", "b");
}
csharp
(string alpha, string beta) = GetLetters();
Console.WriteLine($"alpha:{alpha}, beta:{beta}"); // alpha:a, beta:b

当然也可以直接将方法的返回值赋给一个元组变量。

csharp
var letters = GetLetters();
Console.WriteLine($"letters.Alpha:{letters.Alpha}, letters.Beta:{letters.Beta}"); // letters.Alpha:a, letters.Beta:b

另外,自定义类型也可以支持解构,只需要实现 Deconstruct 方法。示例如下:

csharp
public class Point
{
    public Point(double x, double y)
        => (X, Y) = (x, y);

    public double X { get; }
    public double Y { get; }

    public void Deconstruct(out double x, out double y) =>
        (x, y) = (X, Y);
}

参考:《.NET Core 实战:手把手教你掌握 380 个精彩案例》 -- 周家安 著