元组能够组合不同类型的对象。使用数组可以组合相同类型的对象,而元组允许使用类型的不同组合。元组有助于减少以下两个需求:
- 定义自定义类或结构,以返回多个值
- 定义参数,从方法中返回多个值
自从.NET Framework 4.0 版本以来,元组就以泛型Tuple类的形式存在。然而,它们并没有得到广泛使用,因为元组的不同对象可以通过Item1、Item2、Item3等属性访问,这既不吸引人,也没有提供任何关于其含义的信息。
这在C# 7 中发生了变化,C# 7 提供了在编程语言中集成的元组功能,这有了很大的改进,如下一个示例所示,它使用了一个简单的不可变的Person类:
public class person
{
public person (string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
public string FirstName { get; }
public string LastName { get; }
public override string ToString () => $"{FirstName} {LastName}"
}
元组的声明和初始化
可以使用圆括号声明一个元组,并使用通过括号创建的元组字面量来初始化。在下面的代码片段中,左侧声明了一个元组变量t,其中包含了一个字符串、一个int和一个Person。右边使用一个元组字面量来创建一个元组,它包含字符串magic、数字4、以及使用Person类的构造函数初始化的Person对象。访问元组时,可以使用变量t以及在括号中声明的成员(本例中为s、i和p)。
public static void IntroTuples()
{
(string s,int i,Person p) t = ("magic",42,new Person("Stephanie","Nagel"));
System.Console.WriteLine($"s: {t.s}, i: {t.i}, p: {t.p}");
}
运行应用程序时,输出显示了元组的值:
s: magic, i: 42, p: Stephanie Nagel
元组字面量也可以分配给元组变量,而不需要声明它的成员。这样,元组的成员就可以使用ValueTuple结构的成员名称来访问:Item1、Item2和Item3。
var t2 = ("magic",42,new Person("Stephanie","Nagel"));
System.Console.WriteLine($"string: {t2.Item1},int: {t2.Item2},person: {t2.Item3}");
可以通过定义名称后跟冒号,来为元组字面量中的元组指定名称,它与对象字面量的语法相同:
var t3 = (s: "magicj", i: 42, p: new Person("Matthias","Nagel"));
System.Console.WriteLine($"s: {t3.s}, i: {t3.i}, p: {t3.p}");
有了这些,名字只是一种方便的方式。当类型匹配时,可以将一个元组分配给另一个元组;名字并不重要:
(string astring,int anumber,Person aperson) t4 = t3;
System.Console.WriteLine($"s: {t4.astring}, i: {t4.anumber}, p: {t4.aperson}");
元组解构
还可以将元组分解为变量。为此,只需要从前面的代码示例中删除元组变量,并在括号中定义变量名。然后可以直接访问变量,其中包含元组部分的值:
public static void TupleDeconstruction()
{
(string s,int i,Person p) = ("magic",42,new Person("Stephanie","Nagel"));
System.Console.WriteLine($"s: {s}, i: {i}, p: {p}");
}
还可以使用var关键字声明解构的变量;类型由元组字面量定义。还可以在初始化之前声明变量,并将元组分解为现有变量: