Tuple VS ValueTuple(元组类 VS 值元组)

2023-11-06

Tuple VS ValueTuple(元组类 VS 值元组)


C#4.0增加了特性Tuple元组,C#7.0对元组进行了优化:ValueTuple.

Tuple

Tuple是C# 4.0时出的新特性,.Net Framework 4.0以上版本可用。

元组是一种数据结构,具有特定数量和元素序列。比如设计一个三元组数据结构用于存储学生信息,一共包含三个元素,第一个是名字,第二个是年龄,第三个是身高。

元组的具体使用如下:

1.创建元组

默认情况.Net Framework元组仅支持1到7个元组元素,如果有8个元素或者更多,需要使用Tuple的嵌套和Rest属性去实现。另外Tuple类提供创造元组对象的静态方法。

  • 利用构造函数创建
var testTuple6 = new Tuple<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");

var testTuple10 = new Tuple<int, int, int, int, int, int, int, Tuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new Tuple<int, int, int>(8, 9, 10));
Console.WriteLine($"Item 1: {testTuple10.Item1}, Item 10: {testTuple10.Rest.Item3}");
  • 利用Tuple
var testTuple6 = Tuple.Create<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");

var testTuple8 = Tuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
Console.WriteLine($"Item 1: {testTuple8.Item1}, Item 8: {testTuple8.Rest.Item1}");

2.表示一组数据

如下创建一个元组表示一个学生的三个信息:名字、年龄和身高,而不用单独额外创建一个类.

var studentInfo = Tuple.Create<string, int, uint>("Bob", 28, 175);
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");

3.从方法返回多个值

当一个函数需要返回多个值的时候,一般情况下可以使用out参数,这里可以用元组代替out实现返回多个值。

static Tuple<string, int, uint> GetStudentInfo(string name)
{
    return new Tuple<string, int, uint>("Bob", 28, 175);
}
static void RunTest()
{
    var studentInfo = GetStudentInfo("Bob");
    Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}
//这里构建出来的Tuple类型其实是Tuple<int, int, int, int, int, int, int, Tuple<int>>,因此testTuple8.Rest取到的数据类型是Tuple<int>,因此要想获取准确值需要取Item1属性。

4.用于单参数方法的多值传递

当函数参数仅是一个Object类型时,可以使用元组实现传递多个参数值。

static void WriteStudentInfo(Object student)
{
    var studentInfo = student as Tuple<string, int, uint>;
    Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}
static void RunTest()
{
    var t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(WriteStudentInfo));
    t.Start(new Tuple<string, int, uint>("Bob", 28, 175));
    while (t.IsAlive)
    {
        System.Threading.Thread.Sleep(50);
    }
}

缺点

  • 访问元素的时候只能通过ItemX去访问,使用前需要明确元素顺序,属性名字没有实际意义,不方便记忆;
  • 最多有八个元素,要想更多只能通过最后一个元素进行嵌套扩展;
  • Tuple是一个引用类型,不像其它的简单类型一样是值类型,它在堆上分配空间,在CPU密集操作时可能有太多的创建和分配工作。

ValueTuple

ValueTuple是C# 7.0的新特性之一,.Net Framework 4.7以上版本可用。

值元组也是一种数据结构,用于表示特定数量和元素序列,但是是和元组类不一样的,主要区别如下:

  • 值元组是结构,是值类型,不是类,而元组(Tuple)是类,引用类型;
  • 值元组元素是可变的,不是只读的,也就是说可以改变值元组中的元素值;
  • 值元组的数据成员是字段不是属性。

值元组的具体使用如下:

1.创建值元组

和元组类一样,.Net Framework值元组也只支持1到7个元组元素,如果有8个元素或者更多,需要使用值元组的嵌套和Rest属性去实现。另外ValueTuple类可以提供创造值元组对象的静态方法。

  • 利用构造函数创建元组:
var testTuple6 = new ValueTuple<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}"); 

var testTuple10 = new ValueTuple<int, int, int, int, int, int, int, ValueTuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new ValueTuple <int, int, int>(8, 9, 10));
Console.WriteLine($"Item 1: {testTuple10.Item1}, Item 10: {testTuple10.Rest.Item3}");
  • 利用Tuple静态方法构建元组,最多支持八个元素:
var testTuple6 = ValueTuple.Create<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}"); 

var testTuple8 = ValueTuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
Console.WriteLine($"Item 1: {testTuple8.Item1}, Item 8: {testTuple8.Rest.Item1}");
//注意这里构建出来的Tuple类型其实是Tuple<int, int, int, int, int, int, int, Tuple<int>>,因此testTuple8.Rest取到的数据类型是Tuple<int>,因此要想获取准确值需要取Item1属性。

优化区别:当构造出超过7个元素以上的值元组后,可以使用接下来的ItemX进行访问嵌套元组中的值,对于上面的例子,要访问第十个元素,既可以通过testTuple10.Rest.Item3访问,也可以通过testTuple10.Item10来访问。

var testTuple10 = new ValueTuple<int, int, int, int, int, int, int, ValueTuple<int, int, int>>(1, 2, 3, 4, 5, 6, 7, new ValueTuple<int, int, int>(8, 9, 10));
Console.WriteLine($"Item 10: {testTuple10.Rest.Item3}, Item 10: {testTuple10.Item10}");

2.表示一组数据

如下创建一个值元组表示一个学生的三个信息:名字、年龄和身高,而不用单独额外创建一个类。

var studentInfo = ValueTuple.Create<string, int, uint>("Bob", 28, 175);
Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");

3.从方法返回多个值

值元组也可以在函数定义中代替out参数返回多个值。

static ValueTuple<string, int, uint> GetStudentInfo(string name)
{
    return new ValueTuple <string, int, uint>("Bob", 28, 175);
}
static void RunTest()
{
    var studentInfo = GetStudentInfo("Bob");
    Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}

优化区别:返回值可以不明显指定ValueTuple,使用新语法(,)代替,如(string, int, uint):

static (string, int, uint) GetStudentInfo1(string name)
{
    return ("Bob", 28, 175);
}
static void RunTest1()
{
    var studentInfo = GetStudentInfo1("Bob");
    Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}

调试查看studentInfo的类型就是ValueType三元组.

优化区别:返回值可以指定元素名字,方便理解记忆赋值和访问:

static (string name, int age, uint height) GetStudentInfo1(string name)
{
    return ("Bob", 28, 175);
}
static void RunTest1()
{
    var studentInfo = GetStudentInfo1("Bob");
    Console.WriteLine($"Student Information: Name [{studentInfo.name}], Age [{studentInfo.age}], Height [{studentInfo.height}]");
}

4.用于单参数方法的多值传递

当函数参数仅是一个Object类型时,可以使用值元组实现传递多个值。

static void WriteStudentInfo(Object student)
{
    var studentInfo = (ValueTuple<string, int, uint>)student;
    Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
}
static void RunTest()
{
    var t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(WriteStudentInfo));
    t.Start(new ValueTuple<string, int, uint>("Bob", 28, 175));
    while (t.IsAlive)
    {
        System.Threading.Thread.Sleep(50);
    }
}

5.解构ValueTuple

可以通过var (x, y)或者(var x, var y)来解析值元组元素构造局部变量,同时可以使用符号”_”来忽略不需要的元素

static (string name, int age, uint height) GetStudentInfo1(string name)
{
    return ("Bob", 28, 175);
}

static void RunTest1()
{
    var (name, age, height) = GetStudentInfo1("Bob");
    Console.WriteLine($"Student Information: Name [{name}], Age [{age}], Height [{height}]");

    (var name1, var age1, var height1) = GetStudentInfo1("Bob");
    Console.WriteLine($"Student Information: Name [{name1}], Age [{age1}], Height [{height1}]");

    var (_, age2, _) = GetStudentInfo1("Bob");
    Console.WriteLine($"Student Information: Age [{age2}]");
}

总结

由上所述,ValueTuple使C#变得更简单易用。较Tuple相比主要好处如下:

  • ValueTuple支持函数返回值新语法”(,)”,使代码更简单;
  • 能够给元素命名,方便使用和记忆,这里需要注意虽然命名了,但是实际上value tuple没有定义这样名字的属性或者字段,真正的名字仍然是ItemX,所有的元素名字都只是设计和编译时用的,不是运行时用的(因此注意对该类型的序列化和反序列化操作);
  • 可以使用解构方法更方便地使用部分或全部元组的元素;
  • 值元组是值类型,使用起来比引用类型的元组效率高,并且值元组是有比较方法的,可以用于比较是否相等,详见:https://msdn.microsoft.com/en-us/library/system.valuetuple。

原文:http://www.cnblogs.com/lavender000/p/6916157.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Tuple VS ValueTuple(元组类 VS 值元组) 的相关文章

随机推荐

  • ThreadLocal和ThreadLocalMap

    1 ThreadLocal是什么 是用来存放我们需要能够线程隔离的变量的 那就是线程本地变量 也就是说 当我们把变量保存在ThreadLocal当中时 就能够实现这个变量的线程隔离了 entry中的key使用了弱引用 static clas
  • 系统之家装机大师如何制作U盘启动盘?

    U盘的用途非常广泛 现在很多人都会使用U盘重装系统 那就需要先把U盘制作成U盘启动盘来重装系统 那要如何制作U盘启动盘呢 下面小编就教教大家使用系统之家装机大师制作U盘启动盘的方法 系统之家一键重装系统工具下载 系统之家装机大师官方版下载1
  • 【Redis学习笔记】2:认识Redisson及其分布式锁RLock.lock()

    Redisson和Jedis类似 都是用Java实现的操作Redis的客户端 但是使用场景不同 Redisson更多用在分布式场景下 功能可以看wiki Jedis更多用在单机场景下 1 Java接入Redisson 以Spring Boo
  • SpringMVC——静态资源访问之

    web xml 配置
  • 关于不设置div高度时,背景图片或背景颜色不显示的问题

    在写一个网页时 遇到div高度不定时 即高度设为auto 或者不设置时 加入的的背景图片不能显示的问题 在查阅相关资料后发现几种解决方法 出现这种情况有两个前提 1 外部的div没有设置高度 2 内部div浮动 解决方法 1 最直接的方法
  • 多元时间序列

    目录 多元时间序列 RBF径向基神经网络多变量时间序列预测 Matlab完整程序 预测结果 基本介绍 程序设计 参考资料 多元时间序列 RBF径向基神经网络多变量时间序列预测 Matlab完整程序 预测结果 基本介绍 多元时间序列 Matl
  • docker修改镜像的存储位置_Docker中修改镜像、容器的存放目录

    系统是CentOS7 DOCKER 1 13版本 之后版本未测试过 以上步骤在该操作系统和Docker版本下已经测试过 解决方案 在默认情况下 Docker镜像和容器的默认存放位置为 var lib docker 一般根下分区我们不会给太大
  • 爬虫实战

    爬51job url里的内容 项目的开发工具选择Requests模块和BeautifulSoup模块实现爬虫开发与数据清洗 数据存储选择Sqlalchemy框架 数据库选择MySQL 获取城市编号 1 观察搜索页的URL地址 控制变量 观察
  • docker数据管理---数据卷,数据卷容器

    在Docker中 数据卷 data volumes 和数据卷容器 data volume containers 是用于在容器之间共享和持久化数据的两种不同的机制 一 数据卷 数据卷是一个特殊的目录或目录 可以绕过容器文件系统的常规层 直接在
  • 输入一行字符,统计其中各种字符个数(C语言)

    输入一行字符 统计其中各种字符个数 编译环境VS2017 其中输出英文字母 数字 空格以及其他字符的个数 需要注意的是fgets 函数的使用 会在字符串末尾 0前 读入我们在键盘上敲的回车即换行符 n include
  • 自制Web桌面日历

    想要一个带农历的桌面日历 google了半天也没有找到中意的 但是经常浏览网站的时候发现很多不错的日历 直接保存到我的桌面上不就完了吗 下面是具体操作 将中意的日历页面 查看源文件 看是否可以看到script文件 如果可以 就保存到本地 用
  • 【雕爷学编程】Arduino动手做(202)---热释电效应、热释电元件与HC-SR505运动传感器模块

    37款传感器与模块的提法 在网络上广泛流传 其实Arduino能够兼容的传感器模块肯定是不止37种的 鉴于本人手头积累了一些传感器和执行器模块 依照实践出真知 一定要动手做 的理念 以学习和交流为目的 这里准备逐一动手试试多做实验 不管成功
  • vba中find方法查找1

  • QML ListView实现树形效果

    转自 http blog huati365 com 5jELjzLwnx3YGw import QtQuick 2 11 import QtQuick Controls 2 2 import QtQuick Controls Materia
  • Android抓包工具——Fiddler

    前言 在平时和其他大佬交流时 总会出现这么些话 抓个包看看就知道哪出问题了 抓流量啊 payload都在里面 这数据流怎么这么奇怪 这里出现的名词 其实都是差不多的意思啊 这都跟抓包这个词有关 说到抓包呢我们今天就先来了解一下抓包的一些基础
  • MySQL组成

    MySQL 的组成分为两部分 服务器端 服务的提供 相当于卖家 客户端 服务的使 相当于买家 消费者 服务器端只能有一个 而客户端可以有多个 安装了 MySQL 说明我们既是服务器端又是客户端 服务器端的服务体现就是 客户端是使 MySQL
  • 微软亚洲研究院实习生面试

    上周说到微软亚洲研究院 MSRA 一下就简称MSRA吧 网络面试我这边因为连不上而要重新安排面试 周五HR就给我电话约好今天中午1 00 3 00重新面试 于是提前做好各种准备 找了个拉ADSL的宿舍来上网 然后用了人家带摄像头的笔记本 还
  • B站创建视频分集播放列表

    上传视频在B站上创建视频分集列表方法 上传时创建分集列表 1 打开B站 2 登录B站后 点击投稿上传视频 3 上传视频或把视频直接拖拽到页面里 4 点击上传第一个视频后页面下会出现一个 号的按钮 点击 继续上传 上传视频就会出现两个正在上传
  • 浅谈 Node.js 热更新

    大厂技术 高级前端 Node进阶 点击上方 程序员成长指北 关注公众号 回复1 加入高级Node交流群 记得在 15 16 年那会 Node js 刚起步的时候 我在去前东家的入职面试也被问到了要如何实现 Node js 服务的热更新 其实
  • Tuple VS ValueTuple(元组类 VS 值元组)

    Tuple VS ValueTuple 元组类 VS 值元组 文章目录 Tuple VS ValueTuple 元组类 VS 值元组 Tuple 1 创建元组 2 表示一组数据 3 从方法返回多个值 4 用于单参数方法的多值传递 缺点 Va