ZetCode

C# 元组

最后修改于 2024 年 1 月 26 日

在本文中,我们将展示如何在 C# 中使用元组类型。

元组 是未命名但有序的值的分组。 这些值可以是不同的类型。 元组可以是引用类型(由 System.Tuple 支持)或值类型(由 System.ValueTuple 支持)。

自 C# 7 以来,元组已成为语言语法的一部分。 在本文中,我们将重点关注较新的语法。 新语法使用圆括号来定义和使用元组。

C# 元组简单示例

在以下示例中,我们使用旧方法和新方法创建一个新元组。

Program.cs
var u1 = Tuple.Create("John", "Done", "gardener");
Console.WriteLine($"{u1.Item1} {u1.Item2} is a {u1.Item3}");

var u2 = ("Roger", "Roe", "driver"); 
Console.WriteLine($"{u2.Item1} {u2.Item2} is a {u2.Item3}");

我们创建两个元组并将它们的内容打印到控制台。

var u1 = Tuple.Create("John", "Done", "gardener");
Console.WriteLine($"{u1.Item1} {u1.Item2} is a {u1.Item3}");

这是创建元组的旧方法。 创建 System.Tuple 的新实例。 元组的成员通过 ItemN 成员访问。 此元组是引用类型。

var u2 = ("Roger", "Roe", "driver"); 
Console.WriteLine($"{u2.Item1} {u2.Item2} is a {u2.Item3}");

这是创建元组的最新方法。 此元组是值类型。 我们使用 Item1Item2Item3 访问元组字段;但是,可以命名我们的字段。

$ dotnet run
John Done is a gardener
Roger Roe is a driver

C# 元组字段名称

我们可以命名我们的元组字段。

Program.cs
var u1 = (Name: "John Doe", Age: 34);
Console.WriteLine($"{u1.Name} is {u1.Age} years old");

(string Name, int Age) u2 = ("Roger Roe", 55); 
Console.WriteLine($"{u2.Name} is {u2.Age} years old");

var name = "Jane Doe";
var age = 26;

var u3 = (name, age);
Console.WriteLine($"{u3.name} is {u3.age} years old");

该示例显示了命名元组字段的三种不同方法。

var u1 = (Name: "John Doe", Age: 34);

字段名称与它的值用冒号字符分隔。 字段用逗号分隔。

Console.WriteLine($"{u1.Name} is {u1.Age} years old");

这里我们通过它们的名称引用元组字段。

(string Name, int Age) u2 = ("Roger Roe", 55); 

当我们将一个元组分配给另一个元组时,我们在变量名称之前的圆括号内指定名称和类型。

var name = "Jane Doe";
var age = 26;

var u3 = (name, age);

可以从现有变量创建元组。 编译器推断字段的类型。

C# 元组交换值

使用元组,我们可以轻松地交换两个变量的值。

Program.cs
var (x, y) = (11, 2);

Console.WriteLine($"x: {x}");
Console.WriteLine($"y: {y}");

(y, x) = (x, y);

Console.WriteLine($"x: {x}");
Console.WriteLine($"y: {y}");

我们定义并初始化两个变量 xy。 稍后,我们在一行中交换它们的值。

(y, x) = (x, y);

元组允许我们在一行中轻松地交换值。

$ dotnet run 
x: 11
y: 2
x: 2
y: 11

C# 元组解构

我们可以通过一个操作解包元组中的所有项。 这称为元组解构。

Program.cs
var (name1, age1) = ("John Doe", 34);
Console.WriteLine($"{name1} is {age1} years old");

(string name2, int age2) = ("Roger Roe", 55);
Console.WriteLine($"{name2} is {age2} years old");

string name3;
int age3;

(name3, age3) = ("Jane Doe", 26);
Console.WriteLine($"{name3} is {age3} years old");

该示例展示了如何解构元组。

var (name1, age1) = ("John Doe", 34);

元组字段值存储在 name1age1 变量中。 我们一步完成变量定义和赋值。

(string name2, int age2) = ("Roger Roe", 55);

这里我们显式指定变量类型。

string name3;
int age3;

(name3, age3) = ("Jane Doe", 26);

C# 嵌套元组

可以将元组嵌套到其他元组中。

Program.cs
var data = ((1, 2, 3), (3, 4, 5), (6, 7, 8));
Console.WriteLine(data);

Console.WriteLine(data.Item1);
Console.WriteLine(data.Item2);
Console.WriteLine(data.Item1);

Console.WriteLine(data.Item1.Item1);
Console.WriteLine(data.Item2.Item3);

在该示例中,我们有一个元组,其中包含三个由三个值组成的嵌套元组。

Console.WriteLine(data.Item1);

在这里我们得到第一个嵌套元组:(1, 2, 3)

Console.WriteLine(data.Item1.Item1);
Console.WriteLine(data.Item2.Item3);

在这里我们获得第一个嵌套元组的第一个和第三个元素。

$ dotnet run
((1, 2, 3), (3, 4, 5), (6, 7, 8))
(1, 2, 3)
(3, 4, 5)
(1, 2, 3)
1
5

C# 元组作为函数参数

元组可以是函数参数。

Program.cs
ShowInfo(("John", "Doe", "programmer"));
ShowInfo(("Roger", "Roe", "driver"));
ShowInfo(("Jane", "Doe", "teacher"));

void ShowInfo((string FirstName, string LastName, string Occupation) u)
{
    Console.WriteLine($"{u.FirstName} {u.LastName} is a {u.Occupation}");
}

在该示例中,我们将元组传递给 ShowInfo 函数,该函数从其字段构建并打印消息。

C# 元组作为返回值

可以从函数返回元组。

Program.cs
var user = GetUser();
Console.WriteLine($"{user.FirstName} {user.LastName} is a {user.Occupation}");

(string FirstName, string LastName, string Occupation) GetUser()
{
    return ("John", "Doe", "programmer");
}

GetUser 的返回类型是一个具有三个字段的元组。

C# 元组 & 模式匹配

模式是一种语法形式,可用于表达要与传入数据进行比较的数据的形状。 元组是可以用于模式匹配的模式之一。

Program.cs
var rand = new Random();

List<string> opts = ["rock", "paper", "scissors"];

string p1 = opts[rand.Next(opts.Count)];
string p2 = opts[rand.Next(opts.Count)];

Console.WriteLine($"player 1 has {p1}, player 2 has {p2}");

string res = RockPaperScissors(p1, p2);
Console.WriteLine(res);

string RockPaperScissors(string player1, string player2) => (player1, player2) switch
{
    ("rock", "paper") => "Rock is covered by paper. Player 2 wins",
    ("rock", "scissors") => "Rock breaks scissors. Player 1 wins.",
    ("paper", "rock") => "Paper covers rock. Player 1 wins.",
    ("paper", "scissors") => "Paper is cut by scissors.  Player 2 wins.",
    ("scissors", "rock") => "Scissors are broken by rock.  Player 2 wins.",
    ("scissors", "paper") => "Scissors cut paper. Player 1 wins.",
    (_, _) => "tie"
};

这是一个简单的石头剪刀布游戏框架。

string RockPaperScissors(string player1, string player2) => (player1, player2) switch
{
    ("rock", "paper") => "Rock is covered by paper. Player 2 wins",
    ("rock", "scissors") => "Rock breaks scissors. Player 1 wins.",
    ("paper", "rock") => "Paper covers rock. Player 1 wins.",
    ("paper", "scissors") => "Paper is cut by scissors.  Player 2 wins.",
    ("scissors", "rock") => "Scissors are broken by rock.  Player 2 wins.",
    ("scissors", "paper") => "Scissors cut paper. Player 1 wins.",
    (_, _) => "tie"
};

我们在 switch 表达式中使用元组模式。 元组表示两个玩家的选择。 每个 switch 表达式分支代表游戏中可能出现的场景。

$ dotnet run
player 1 has rock, player 2 has scissors
Rock breaks scissors. Player 1 wins.
$ dotnet run
player 1 has paper, player 2 has rock
Paper covers rock. Player 1 wins.
$ dotnet run
player 1 has scissors, player 2 has rock
Scissors are broken by rock.  Player 2 wins.

来源

元组类型 - 语言参考

在本文中,我们使用 C# 中的元组。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程