什么是元组
元组是 C# 提供的简单定义的类型,早期版本为 System.Tuple
,使用该类型可以简化类型的定义。
1 | // 姓名 性别 出生日期 |
如上,可以组装多个类型成为一个新的类型,可以应用在多返回值或一些数组集合场景下。
1 | // 多返回值:是否执行成功 错误信息 |
但是该类型使用时还是有一些缺陷,特别是通过 Item{n}
标记元素,没有具体的含义在使用中就比较容易出错。
另外,其泛型参数只提供了 7 个,如果超过 7 个,我们就要使用第 8 个泛型参数使用 System.Tuple
类型进行嵌套,例如:
1 | // 定义多个参数 |
所以微软在后来提供了 System.ValueTuple
类型,取代了 System.Tuple
,我们可以通过 NuGet
引用 System.ValueTuple
使用。
如上图所示,其标记的支持 .NET Framework
的最低版本为 .NET Framework 4.5
,但实际上我们给 .NET Framework 4.0
的项目引用依然是可以正常使用的。另外如果想在 .NET Framework 3.5
的项目中使用,可以引用上图中的 ValueTupleBridge
。
ValueTuple 的语法
首先我们使用 NuGet
添加对 System.ValueTuple
的引用,我们可以将以上 Tuple 部分定义的内容进行简单的重写:
1 | // 多返回值:是否执行成功 错误信息 |
1 | // 定义多个参数 |
此外我们还可以用多种方式来声明 System.ValueTuple
:
- 将元组赋给单独声明的变量
1
2(string name, bool sex, DateTime birthday) = ("John", true, new DateTime(1992, 02, 02));
Console.WriteLine($"{name} is a good {(sex ? "boy" : "girl")} and {(sex ? "his" : "her")} birthday is on {birthday.ToString("MM.dd")}"); - 将元组赋给预声明的变量
1
2
3
4
5string name;
bool sex;
DateTime birthday;
(name, sex, birthday) = ("John", true, new DateTime(1992, 02, 02));
Console.WriteLine($"{name} is a good {(sex ? "boy" : "girl")} and {(sex ? "his" : "her")} birthday is on {birthday.ToString("MM.dd")}"); - 将元组赋给单独声明和隐式类型的变量
1
2(var name, var sex, var birthday) = ("John", true, new DateTime(1992, 02, 02));
Console.WriteLine($"{name} is a good {(sex ? "boy" : "girl")} and {(sex ? "his" : "her")} birthday is on {birthday.ToString("MM.dd")}"); - 将元组赋给单独声明和隐式类型的变量,但只用一个
var
1
2var (name, sex, birthday) = ("John", true, new DateTime(1992, 02, 02));
Console.WriteLine($"{name} is a good {(sex ? "boy" : "girl")} and {(sex ? "his" : "her")} birthday is on {birthday.ToString("MM.dd")}"); - 声明具名元组,将元组值赋给它,按名称访问元组项
1
2(string name, bool sex, DateTime birthday) person = ("John", true, new DateTime(1992, 02, 02));
Console.WriteLine($"{person.name} is a good {(person.sex ? "boy" : "girl")} and {(person.sex ? "his" : "her")} birthday is on {person.birthday.ToString("MM.dd")}"); - 声明包含具名元组项的元组,将其赋给隐式类型的变量,按名称访问元组项
1
2var person = (name: "John", sex: true, birthday: new DateTime(1992, 02, 02));
Console.WriteLine($"{person.name} is a good {(person.sex ? "boy" : "girl")} and {(person.sex ? "his" : "her")} birthday is on {person.birthday.ToString("MM.dd")}"); - 将元组项未具名的元组赋给隐式类型的变量,通过项编号属性访问单独的元素
1
2var person = ("John", true, new DateTime(1992, 02, 02));
Console.WriteLine($"{person.Item1} is a good {(person.Item2 ? "boy" : "girl")} and {(person.Item2 ? "his" : "her")} birthday is on {person.Item3.ToString("MM.dd")}"); - 将元组项具名的元组赋给隐式类型的变量,但还是通过项编号
1
2var person = (name: "John", sex: true, birthday: new DateTime(1992, 02, 02));
Console.WriteLine($"{person.Item1} is a good {(person.Item2 ? "boy" : "girl")} and {(person.Item2 ? "his" : "her")} birthday is on {person.Item3.ToString("MM.dd")}"); - 赋值时使用下划线丢弃元组的一部分(弃元)
1
(string name, bool sex, DateTime birthday, _) = ("John", true, new DateTime(1992, 02, 02), "China");
- 通过变量和属性名推断元组项名称(
C# 7.1
新增)1
2
3
4
5string name = "John";
bool sex = true;
DateTime birthday = new DateTime(1990, 01, 01);
var person = (name, sex, birthday);
Console.WriteLine($"{person.name} is a good {(person.sex ? "boy" : "girl")} and {(person.sex ? "his" : "her")} birthday is on {person.birthday.ToString("MM.dd")}");注意:
- 元组是在对象中封装数据的轻量级方案,元组数据项的类型没有限制,但是他们的类型是由编译器决定,不能在运行时改变。
- 如果需要对封装的数据关联行为(事件、方法),应该创建一个类而不是使用元组。
- 元组
System.ValueTuple
类似结构体,如果将一个元组赋值给另外一个元组,其是值传递而非引用传递。