元祖类型
引用自:C#:元组 - 码上的飞鱼 - 博客园 (cnblogs.com)
引用自:C#——元组类型_吴俊荣的博客-CSDN博客_c# 元组
C#——元组类型
元组功能在 C# 7.0 及更高版本中可用,它提供了简洁的语法,用于将多个数据元素分组成一个轻型数据结构。 下面的示例演示了如何声明元组变量、对它进行初始化并访问其数据成员:
(double, int) t1 = (4.5, 3); Console.WriteLine($"Tuple with elements {t1.Item1} and {t1.Item2}."); // Output: // Tuple with elements 4.5 and 3. (double Sum, int Count) t2 = (4.5, 3); Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}."); // Output: // Sum of 3 elements is 4.5.
如前面的示例所示,若要定义元组类型,需要指定其所有数据成员的类型,或者,可以指定字段名称。 虽然不能在元组类型中定义方法,但可以使用 .NET 提供的方法,如下面的示例所示:
(double, int) t = (4.5, 3); Console.WriteLine(t.ToString()); Console.WriteLine($"Hash code of {t} is {t.GetHashCode()}."); // Output: // (4.5, 3) // Hash code of (4.5, 3) is 718460086.
从 C# 7.3 开始,元组类型支持相等运算符 == 和 !=。
元组类型是值类型;元组元素是公共字段。 这使得元组为可变的值类型。
元组功能需要 System.ValueTuple 类型和相关的泛型类型(例如 System.ValueTuple<T1,T2>),这些类型在 .NET Core 和 .NET Framework 4.7 及更高版本中可用。 若要在面向 .NET Framework 4.6.2 或更早版本的项目中使用元组,请将 NuGet 包 System.ValueTuple 添加到项目。
可以使用任意数量的元素定义元组:
var t = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26); Console.WriteLine(t.Item26); // output: 26
元组的用例
元组最常见的用例之一是作为方法返回类型。 也就是说,你可以将方法结果分组为元组返回类型,而不是定义 out 方法参数,如以下示例所示:
var xs = new[] { 4, 7, 9 }; var limits = FindMinMax(xs); Console.WriteLine($"Limits of [{string.Join(" ", xs)}] are {limits.min} and {limits.max}"); // Output: // Limits of [4 7 9] are 4 and 9 var ys = new[] { -9, 0, 67, 100 }; var (minimum, maximum) = FindMinMax(ys); Console.WriteLine($"Limits of [{string.Join(" ", ys)}] are {minimum} and {maximum}"); // Output: // Limits of [-9 0 67 100] are -9 and 100 (int min, int max) FindMinMax(int[] input) { if (input is null || input.Length == 0) { throw new ArgumentException("Cannot find minimum and maximum of a null or empty array."); } var min = int.MaxValue; var max = int.MinValue; foreach (var i in input) { if (i < min) { min = i; } if (i > max) { max = i; } } return (min, max); }
如前面的示例所示,可以直接使用返回的元组实例,或者可以在单独的变量中析构它。
还可以使用元组类型,而不是匿名类型;例如,在 LINQ 查询中。
通常,你会使用元组对相关的数据元素进行松散分组。 这通常在专用和内部实用工具方法中有用。 对于公共 API 用例,请考虑定义类或结构类型。
元组字段名称
可以在元组初始化表达式中或元组类型的定义中显式指定元组字段的名称,如下面的示例所示:
var t = (Sum: 4.5, Count: 3); Console.WriteLine($"Sum of {t.Count} elements is {t.Sum}."); (double Sum, int Count) d = (4.5, 3); Console.WriteLine($"Sum of {d.Count} elements is {d.Sum}.");
从 C# 7.1 开始,如果未指定字段名称,则可以根据元组初始化表达式中相应变量的名称推断出此名称,如下面的示例所示:
var sum = 4.5; var count = 3; var t = (sum, count); Console.WriteLine($"Sum of {t.count} elements is {t.sum}.");
这称为元组投影初始值设定项。 在以下情况下,变量名称不会被投影到元组字段名称中:
候选名称是元组类型的成员名称,例如 Item3、ToString 或 Rest。
候选名称是另一元组的显式或隐式字段名称的重复项。
在这些情况下,你可以显式指定字段的名称,或按字段的默认名称访问字段。
元组字段的默认名称为 Item1、Item2、Item3 等。 始终可以使用字段的默认名称,即使字段名称是显式指定的或推断出的,如下面的示例所示:
var a = 1; var t = (a, b: 2, 3); Console.WriteLine($"The 1st element is {t.Item1} (same as {t.a})."); Console.WriteLine($"The 2nd element is {t.Item2} (same as {t.b})."); Console.WriteLine($"The 3rd element is {t.Item3}."); // Output: // The 1st element is 1 (same as 1). // The 2nd element is 2 (same as 2). // The 3rd element is 3.
元组赋值和元组相等比较不会考虑字段名称。
在编译时,编译器会将非默认字段名称替换为相应的默认名称。 因此,显式指定或推断的字段名称在运行时不可用。
元组赋值和析构
C# 支持满足以下两个条件的元组类型之间的赋值:
两个元组类型有相同数量的元素
对于每个元组位置,右侧元组元素的类型与左侧相应的元组元素的类型相同或可以隐式转换为左侧相应的元组元素的类型
元组元素是按照元组元素的顺序赋值的。 元组字段的名称会被忽略且不会被赋值,如下面的示例所示:
(int, double) t1 = (17, 3.14); (double First, double Second) t2 = (0.0, 1.0); t2 = t1; Console.WriteLine($"{nameof(t2)}: {t2.First} and {t2.Second}"); // Output: // t2: 17 and 3.14 (double A, double B) t3 = (2.0, 3.0); t3 = t2; Console.WriteLine($"{nameof(t3)}: {t3.A} and {t3.B}"); // Output: // t3: 17 and 3.14
还可以使用赋值运算符 = 在单独的变量中析构元组实例。 为此,可以使用以下方式之一进行操作:
- 在括号内显式声明每个变量的类型:
var t = ("post office", 3.6); (string destination, double distance) = t; Console.WriteLine($"Distance to {destination} is {distance} kilometers."); // Output: // Distance to post office is 3.6 kilometers.
- 在括号外使用 var 关键字来声明隐式类型化变量,并让编译器推断其类型:
var t = ("post office", 3.6); var (destination, distance) = t; Console.WriteLine($"Distance to {destination} is {distance} kilometers."); // Output: // Distance to post office is 3.6 kilometers.
- 使用现有变量:
var destination = string.Empty; var distance = 0.0; var t = ("post office", 3.6); (destination, distance) = t; Console.WriteLine($"Distance to {destination} is {distance} kilometers."); // Output: // Distance to post office is 3.6 kilometers.
元组相等
从 C# 7.3 开始,元组类型支持 == 和 != 运算符。 这些运算符按照元组元素的顺序将左侧操作数的成员与相应的右侧操作数的成员进行比较。
(int a, byte b) left = (5, 10); (long a, int b) right = (5, 10); Console.WriteLine(left == right); // output: True Console.WriteLine(left != right); // output: False var t1 = (A: 5, B: 10); var t2 = (B: 5, A: 10); Console.WriteLine(t1 == t2); // output: True Console.WriteLine(t1 != t2); // output: False
如前面的示例所示,== 和 != 操作不会考虑元组字段名称
同时满足以下两个条件时,两个元组可比较:
- 两个元组具有相同数量的元素。 例如,如果 t1 和 t2 具有不同数目的元素,t1 != t2 则不会进行编译。
- 对于每个元组位置,可以使用 == 和 != 运算符对左右侧元组操作数中的相应元素进行比较。 例如,(1, (2, 3)) == ((1, 2), 3) 不会进行编译,因为 1 不可与 (1, 2) 比较。
== 和 != 运算符将以短路方式对元组进行比较。 也就是说,一旦遇见一对不相等的元素或达到元组的末尾,操作将立即停止。 但是,在进行任何比较之前,将对所有元组元素进行计算,如以下示例所示:
Console.WriteLine((Display(1), Display(2)) == (Display(3), Display(4))); int Display(int s) { Console.WriteLine(s); return s; } // Output: // 1 // 2 // 3 // 4 // False
元组作为 out 参数
通常,你会将具有 out 参数的方法重构为返回元组的方法。 但是,在某些情况下,out 参数可以是元组类型。 下面的示例演示了如何将元组作为 out 参数使用:
var limitsLookup = new Dictionary<int, (int Min, int Max)>() { [2] = (4, 10), [4] = (10, 20), [6] = (0, 23) }; if (limitsLookup.TryGetValue(4, out (int Min, int Max) limits)) { Console.WriteLine($"Found limits: min is {limits.Min}, max is {limits.Max}"); } // Output: // Found limits: min is 10, max is 20
元组与 System.Tuple
System.ValueTuple 类型支持的 C# 元组不同于 System.Tuple 类型表示的元组。 主要区别如下:
- ValueTuple 类型是值类型。 Tuple 类型是引用类型。
- ValueTuple 类型是可变的。 Tuple 类型是不可变的。
- ValueTuple 类型的数据成员是字段。 Tuple 类型的数据成员是属性。
======================================================================================================================================================================================================
定义
元组是包含多个字段以表示数据成员的轻量级数据结构。是比 class
和 struct
类型更为简单灵活的数据容器。
元组没有具体类型,只能用var。
- 命名:(old: 38, name: "feige")
- 匿名:(38,"fegei")
语法
//1 var tuple = (a: 5, b: 10); //or var tuple = (5,10); //2 (int a,int b) tuple1 = (5,10); // or (int,int) tuple1 = (5,10);
使用
最简单的数据封装,和数组不同,它可以封装不同的数据类型
即可作为方法的参数,
//static void enter(var student) 不能使用var,没有任何线索,无法推断 //static void enter((int, string, bool) student) static void enter((int height, string name, bool gender) student) { Console.WriteLine(student.name); }
也可以作为方法的返回值:(int, string)
static (int,string,bool) enter(int term) { return (175, "jimmy", true); }
命名元组的新语言和库支持简化了设计工作:与类和结构一样,使用数据结构存储多个元素,但不定义行为。 对这些类型使用元组非常简单明了。 既可以获得静态类型检查的所有好处,又不需要使用更复杂的 class 或 struct 语法来创作类型。 即便如此,元组还是对 private 或 internal 这样的实用方法最有用。 当公共方法返回具有多个元素的值时,请创建用户定义的类型(class 或 struct 类型)。
======================================================================================================================================================================================================
元组这个新特性就是能够一次性返回多个值
1 .使方法可以返回多个返回值而不需要借助out ref关键字。
2 .使方法可以返回多个返回值而不需要借助out ref关键字.Tuple这个泛型类,可以允许我们返回多个参数。
一、什么是元组
元组就是一些对象的集合.在我们编程时,比如一个人的信息,我们常常创建一个Person类去描述一个人.传统的做法如下:
public class Person{ public int ID{get;set;} public string Name{get:set;}} Person a=new Person(){ID=1001 ,Name='CodeL'); Console.WriteLine(a.Name);
那么我们使用元组可以怎么做呢?如下所示
Tuple<int,string> a=new Tuple<int,string>(l001 ,'CodeL); 〃直接使用元组对象,不需要创建自定义的对象 Console.WriteLine(a.ltem2);//lteml代表第一个,Item2代表第二个,每一个元组对象都有一个默认的item属性
由此可见,元组最大的用处就是,不用为了 一些简单的结构或对象而去新建一个类了。
注意的是tuple最多支持8个成员,如果成员超过了8个我们可以将第8个成员当成一个元组,通过元祖的嵌套去完成,如
列如:Tuple<string, int. int. int, int. int, int, Tuple<int. int, int»红色部分是第8个。这里的第八个成员又是一个元组。
二、元组的使用
1、元组对象的创建和遍历
创建元组对象有两种方法,如下:
//通过构造函数创建元组对象 Tuple<string, int. double〉tuple 1 = new Tuple<string, int, double>("数学",100, 100.1); //通过验态函数创建元组对象 Tuple<string, int. double> tuple2 = Tuple.Create<string, int, double*"英语”,200, 200.2); //元组对象的遍历.元组对象有一个默认的ilem属性 Console.WriteLine($"{tuplel .Iteml} {tuplel .Item2) {tuplel .Item3)"); Console.WriteLine(S"{tuple2.ltem1} {luple2.Item2} {Iuple2.ltem3)");
2、元组与数据集合的结合
按照之前创建自定义的数据类型的使用方法,我们一般是使用List<Person> listPerson=new List<Person>();但是通过元组我们如下所
示:
List<Tuple<string, string, int, int. int» listPerson = new List<Tuple<string, string, int, int. int»() ( new Tuple<string, string, int, int, int>("菲菲","女",23,161,50), new Tuple<string, string, int, int, inl>("张三","男",25,171,66), Tuple.Create<string,string,int,int,int>("李四","男”,25,178,78) }; foreach (var item in listPerson) { Console.WriteLine($"{item.lteml) {item.ltem2) {item.ltem3} {item.ltem4) {item.ltem5}");