news 2026/5/12 21:11:08

C#元组类型简介

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C#元组类型简介
  • 元组是 C# 7.0 引入的轻量级数据结构,用于临时组合多个值,无需定义专门的类或结构。
    元组是有序的数据结构,成员按声明/创建时的顺序排列。(这里的元组只指值元组
  • 元组类型在C#7.0前是有一个专门的内置类型,Tuple,但现在不建议使用,新的是ValueTuple
C# 元组家族 ├── Tuple(class,只读,无语法糖)→ 老代码用,不推荐 └── ValueTuple(struct,可修改,有语法糖)→ 你学的就是这个 └── 语法糖:(string Name, int Age) ← 要学的这个

Tuple示例代码

// ❌ 旧式 Tuple,不推荐 Tuple<类型1,类型2,类型3> 变量名 = Tuple.Creat(值1,值2,值3); // 引用类型,在堆上分配 Tuple<string, int> t1 = Tuple.Create("张三", 30); Tuple<string, int> t2 = new Tuple<string, int>("李四", 25); // 访问:只能用 Item1, Item2... Console.WriteLine(t1.Item1); // 张三 Console.WriteLine(t1.Item2); // 30 // 只读,不能修改 // t1.Item1 = "王五"; // ❌ 编译错误 // ✅ 现代 ValueTuple,推荐 (string Name, int Age) modern = ("张三", 30); var modern2 = (Name: "李四", Age: 25);
对比项TupleValueTuple
引入版本C# 4.0 / .NET 4.0C# 7.0 / .NET 4.7
类型class(引用类型)struct(值类型)
内存分配
可变性只读可修改
自定义名称❌ 不支持✅ 支持
语法糖❌ 无(a, b)语法
解构❌ 需手动✅ 原生支持
性能较差较好
推荐度不推荐(旧代码)推荐使用

1元组类型和变量定义

元组定义分为两种方式:

1.先用using定义元祖类型名,再实例化

2.直接实例化

  • 显式实例化(直接写好类型名)
  • 隐式实例化(用var)
//1.先用using给元组类型命名,再实例化 //方式1:不定义元组成员标签名 using 元组类型名 = (类型1, 类型2, 类型3); using tup1 = (string, int); //方式2:定义元组成员标签名 using 元组类型名 = (类型1 标签名1, 类型2 标签名2, 类型3 标签名3); using tup2 = (string Name, int Age); //2.显式定义类型,并实例化 //方式1:不定义元组成员标签名 (类型1,类型2,类型3) 变量名 = (值1, 值2, 值3); (string, int) tup3 = ("hello", 123); //方式2:定义元组成员标签名 (类型1 标签名1, 类型2 标签名2, 类型3 标签名3) 变量名 = (标签名1:值1, 标签名2:值2, 标签名3:值3); (string N, int A) p = (Name: "张三", Age: 30); //3.隐式定义类型,并实例化 //方式1:不定义元组成员标签名 var 变量名 = (值1,值2,值3); //方式2:定义元组成员标签名 var 变量名 = (标签1:值1, 标签2:值2, 标签3:值3);

2元组元素的访问

元组元素访问分为两种情况

  • 类型无标签的(左值无标签),通过变量名.ItemX访问
  • 类型有标签的(左值有标签),通过变量名.ItemX变量名.标签名访问
/* 元祖元素访问: 1.如果左侧是无标签的,只能通过默认的 ItemX 属性访问成员。X是元组的元素序号 注意:元组的元素序号从 1 开始 2.如果左侧是有标签的,既可以通过 元祖名.ItemX 访问,也可以通过 元组名.标签名访问 */ //1.1不定义元组成员标签名 tup1 p0 = ("张三", 30); Console.WriteLine(p0.Item1); //1.2定义元组成员标签名 tup2 p1 = ("张三", 30); Console.WriteLine(p1.Item1); //p1.Item1和p1.Name访问的是一样的元素 Console.WriteLine(p1.Name);

3左右值标签的规则

左值的标签:构成元组的每个类型对应的标签

右值的标签:元组实例化后,值的标签(只方便查看值的含义,无实际语法作用)

/* 给元组变量赋值的时候,右边值的标签没有意义,只是作为一个标记方便查看值代表什么 using 别名定义时指定的标签,相当于左边声明的标签。也遵循同样的原则 左边(或 using 定义的标签)决定你能用什么标签访问,右边只提供值(按位置匹配) */ //1.左无右有 → 只能用 Item(右边标签丢失) (string, int) p2 = (Name: "张三", Age: 30); Console.WriteLine(p2.Item1); // ✅ 张三 // Console.WriteLine(p2.Name); // ❌ 不存在 //2.左有右无 → 用左边的标签 (string Name, int Age) p3 = ("李四", 25); Console.WriteLine(p3.Name); // ✅ 李四 Console.WriteLine(p3.Age); // ✅ 25 //3.左右都有 → 用左边的标签(右边标签被忽略) (string FullName, int Years) p4 = (Name: "王五", Age: 28); Console.WriteLine(p4.FullName); // ✅ 王五 Console.WriteLine(p4.Years); // ✅ 28 // Console.WriteLine(p4.Name); // ❌ 不存在(左边没有 Name) // Console.WriteLine(p4.Age); // ❌ 不存在(左边没有 Age) //4.左右都无 → 只能用 Item (string, int) p5 = ("赵六", 32); Console.WriteLine(p5.Item1); // ✅ 赵六
左边(变量声明)右边(赋值)结果(访问方式)
无标签(string, int)无标签("a",1)只能用Item1, Item2
无标签(string, int)有标签(Name:"a", Age:1)只能用Item1, Item2(右边标签被忽略)
有标签(string N, int A)无标签("a",1)可以用N, AItem1, Item2
有标签(string N, int A)有标签(Name:"a", Age:1)可以用N, A(右边标签被忽略)

4元组解构

元组的解构允许将元组中的元素方便地提取出来,赋值给单独的变量。包括:

  • 位置解构(最常用)
  • 按名称解构(C# 7.3+ 增强支持)
  • 弃元(Discard)

如果学过Python,这和Python的拆包比较像。

4.1位置解构

顺序对应,不关心变量名是否与元组元素名一致

var tuple = (name: "Alice", age: 30); (string personName, int personAge) = tuple; // ✅ 顺序匹配,变量名任意 // ✅ 这行代码做了两件事: // 1. 声明了两个新变量 personName (string) 和 personAge (int) // 2. 把 tuple 的第1个元素赋值给 personName(得到 "Alice") // 3. 把 tuple 的第2个元素赋值给 personAge(得到 30) //等价于 string personName = tuple.Item1; // 或者 tuple.name int personAge = tuple.Item2; // 或者 tuple.age

4.2按名称解构

如果解构目标使用了与元组元素相同的变量名,可以省略赋值,但顺序仍按当前位置匹配,名称仅用于“匹配时隐式类型”的推导,不是硬性要求名称一致。

var tuple = (name: "Alice", age: 30); var (age, name) = tuple; // ❗❗ 注意:age 拿到 "Alice",name 拿到 30,因为顺序匹配,不是按名称匹配! //自动推断变量类型,等价于 var age = tuple.name; var name = tuple.age;

4.3弃元(Discard)

弃元(Discard)是 C# 中用下划线_表示的特殊变量,意思是:明确表示忽略这个值,不使用它

无关名称,只关顺序:var (_, second) = tuple;

var tuple = (name: "Alice", age: 30, city: "Beijing"); // 只想要 name 和 age,忽略 city var (name, age, _) = tuple; // 只想要 name,忽略后面两个 var (name, _, _) = tuple; // 只要第二个元素 var (_, age, _) = tuple;

4.4核心结论

  • 顺序必须一致
  • 解构变量的变量名可以与元组元素名不同
  • 不要以为变量名和元组元素名相同就能自动忽略顺序——顺序永远优先,名称只是 IDE 提示的辅助信息,不是解构匹配的依据。

5元组相等性比较

两个元组比较是否相等,会逐元素比较。两个元组如果结构相同且每个元素都相等,则它们相等。

var a = (Name: "张三", Age: 30); var b = (Name: "张三", Age: 30); Console.WriteLine(a == b); // True(逐元素比较)

6元组可以作为字典的Key

Dictionary<TKey, TValue>要求 Key 类型必须:

  • 正确实现GetHashCode()—— 用于快速查找
  • 正确实现Equals()—— 用于判断相等

ValueTuple已经内置实现了这两者:

// 创建一个以二维坐标为 Key 的字典 var map = new Dictionary<(int X, int Y), string>(); //字典的键是个元组形式 // 添加数据 map[(0, 0)] = "起点"; map[(1, 2)] = "宝箱"; map[(5, 5)] = "Boss"; // 访问 Console.WriteLine(map[(1, 2)]); // 输出: 宝箱 // 检查是否存在 if (map.ContainsKey((1, 2))) { Console.WriteLine("坐标 (1,2) 有东西"); }

7元组作为返回值

这是元组最实用的场景之一:让一个方法返回多个值,而不需要创建专门的类或使用out参数。

7.1无标签版

// 返回两个整数(无标签) static (int, int) GetMinMax(int[] numbers) { int min = numbers.Min(); int max = numbers.Max(); return (min, max); // 返回元组 } // 调用 var result = GetMinMax(new int[] { 3, 1, 4, 1, 5, 9 }); Console.WriteLine($"最小值: {result.Item1}, 最大值: {result.Item2}");

7.2有标签版

// 返回时带标签,调用方可以直接用字段名 static (int Min, int Max) GetMinMax(int[] numbers) { int min = numbers.Min(); int max = numbers.Max(); return (Min: min, Max: max); // 左边标签与右边标签一致 } // 调用 var result = GetMinMax(new int[] { 3, 1, 4, 1, 5, 9 }); Console.WriteLine($"最小值: {result.Min}, 最大值: {result.Max}"); // 也可用 Item Console.WriteLine($"最小值: {result.Item1}"); // 同样有效
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/12 21:08:14

WebPShop完整指南:为Photoshop添加强大的WebP支持插件

WebPShop完整指南&#xff1a;为Photoshop添加强大的WebP支持插件 【免费下载链接】WebPShop Photoshop plug-in for opening and saving WebP images 项目地址: https://gitcode.com/gh_mirrors/we/WebPShop WebPShop是一款专为Adobe Photoshop设计的开源插件&#xff…

作者头像 李华
网站建设 2026/5/12 21:07:12

如何快速安装与配置ClickHouse ODBC驱动:完整指南 [特殊字符]

如何快速安装与配置ClickHouse ODBC驱动&#xff1a;完整指南 &#x1f680; 【免费下载链接】clickhouse-odbc ODBC driver for ClickHouse 项目地址: https://gitcode.com/gh_mirrors/cl/clickhouse-odbc ClickHouse ODBC驱动是连接ClickHouse数据库的关键桥梁&#x…

作者头像 李华
网站建设 2026/5/12 21:06:14

Godot游戏逆向工程终极指南:GDScript Decompiler完整使用教程

Godot游戏逆向工程终极指南&#xff1a;GDScript Decompiler完整使用教程 【免费下载链接】gdsdecomp Godot reverse engineering tools 项目地址: https://gitcode.com/GitHub_Trending/gd/gdsdecomp 想要深入了解Godot引擎游戏的内部结构吗&#xff1f;GDScript Decom…

作者头像 李华
网站建设 2026/5/12 20:58:45

5分钟掌握TEdit地图编辑器:终极泰拉瑞亚世界创作工具

5分钟掌握TEdit地图编辑器&#xff1a;终极泰拉瑞亚世界创作工具 【免费下载链接】Terraria-Map-Editor TEdit - Terraria Map Editor - TEdit is a stand alone, open source map editor for Terraria. It lets you edit maps just like (almost) paint! It also lets you cha…

作者头像 李华