详解C# Tuple VS ValueTuple(元组类 VS 值元组)

C# 7.0已经出来一段时间了,大家都知道新特性里面有个对元组的优化:ValueTuple。这里利用详尽的例子详解Tuple VS ValueTuple(元组类VS值元组),10分钟让你更了解ValueTuple的好处和用法。

如果您对Tuple足够了解,可以直接跳过章节”回顾Tuple”,直达章节”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}");

Note:这里构建出来的Tuple类型其实是Tuple<int, int, int, int, int, int, int, Tuple<int>>,因此testTuple8.Rest取到的数据类型是Tuple<int>,因此要想获取准确值需要取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}]"); }


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密集操作时可能有太多的创建和分配工作。

因此在C# 7.0中引入了一个新的ValueTuple类型,详见下面章节。

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


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325384.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 为文件及文件夹添加权限

/*** 增加权限&#xff0c;使路径可上传文件*/ public static void addChmod777(String filePath) throws IOException {if (!System.getProperty("os.name").startsWith("Win")) {String cmdGrant "chmod 777 " filePath;BaseLogMethod.logIn…

《白鹿原》金句摘抄(八)

人行事不在旁人知道不知道&#xff0c;而在自家知道不知道&#xff1b;自家做下好事刻在自家心里&#xff0c;做下瞎事也刻在自家心里&#xff0c;都抹不掉&#xff1b;其实天知道地也知道&#xff0c;记在天上刻在地上&#xff0c;也是抹不掉的。让所有人都看看&#xff0c;真…

Eclipse把默认为Gbk的编码变为UTF-8

菜单栏Windows–>Preferences,左侧导航栏展开General–>Workspace,修改左下角的Text file encoding&#xff0c;选中Other改为UTF-8即可

从LINQ开始之LINQ to Objects(上)

LINQ概述 LINQ&#xff0c;语言集成查询(Language Integrated Query)&#xff0c;它允许使用C#或VB代码以查询数据库相同的方式来操作不同的数据源。 1.LINQ体系结构 从上图可以看出&#xff0c;LINQ总共包括五个部分&#xff1a;LINQ to Objects、LINQ to DataSets、LINQ to …

Redis 的 8 大应用场景

转载自 Redis 的 8 大应用场景 之前讲过Redis的介绍&#xff0c;及使用Redis带来的优势&#xff0c;这章整理了一下Redis的应用场景&#xff0c;也是非常重要的&#xff0c;学不学得好&#xff0c;能正常落地是关键。 下面一一来分析下Redis的应用场景都有哪些。 1、缓存 …

Nginx 原理

nginx原理一 nginx原理二 详解nginx的master进程和worker进程 深入浅出Nginx 正向代理和反向代理 Nginx实现负载均衡

《狂人日记》金句摘抄(一)

所谓回忆者&#xff0c;虽说可以使人欢欣&#xff0c;有时也不免使人寂寞&#xff0c;使精神的丝缕还牵着已逝的寂寞的时光&#xff0c;又有什么意味呢&#xff0c;药店的柜台正和我一样高&#xff0c;质铺的是比我高一倍我在这一个讲堂中&#xff0c;便须常常随喜我那同学们的…

单点登录终极方案之 CAS 应用及原理

转载自 单点登录终极方案之 CAS 应用及原理 Cookie的单点登录的实现方式很简单&#xff0c;但是也问题颇多。例如&#xff1a;用户名密码不停传送&#xff0c;增加了被盗号的可能。另外&#xff0c;不能跨域&#xff01; 1、基于Cookie的单点登录的回顾 基于Cookie的单点登录…

Ubuntu 中 Apache2 安装、配置、卸载

Ubuntu 中 Apache2 安装、配置、卸载

微软亚太区资料科学总监:R 语言是 VS 生态第一顺位

微软亚太区资料科学总监Graham Williams 微软在2015年并购R语言工具商Revolution Analytics之后&#xff0c;随即在2016年&#xff0c;也开始在自家主力开发工具Visual Studio上&#xff0c;支持R语言。微软将如何定位R语言在微软开发工具链的位置&#xff1f;微软亚太区资料科…

Post请求中加不加@RequestBody的区别和formedata与JSON传递的区别

package com.atguigu.boot.controller;import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController;/*** 创建人 wdl* 创建时间 2021/6/13* 描…

java中如何数组是如何赋值的?

由于数组是引用类型&#xff0c;故无法与变量赋值的方式一样&#xff0c;int a 10;int b a; 那么数组是如何赋值的呢&#xff1f; 是这样赋值的&#xff1a; public static void arrayFuZhi(){//八斤的身高和体重int [] ba {170,80};//九斤的身高和体重与八斤的一样int [] …

从LINQ开始之LINQ to Objects(下)

前言 上一篇《从LINQ开始之LINQ to Objects&#xff08;上&#xff09;》主要介绍了LINQ的体系结构、基本语法以及LINQ to Objects中标准查询操作符的使用方法。 本篇则主要讨论LINQ to Objects中的扩展方法以及延迟加载等方面的内容。 扩展方法 1.扩展方法简介 扩展方法能够向…

Redis Linux 安装运行实战全记录

转载自 Redis Linux 安装运行实战全记录 下载Redis 去Redis官网下载最新的Linux包&#xff0c;Redis官方没有Windows版的下载。 https://redis.io/ 下载后把包上传到Linux服务器。 安装Redis 1、解压Redis包 > tar -zxvf redis-4.0.2.tar.gz2、切换到Redis解压目录 &…

Ubuntu 免密登录

ssh-keygen的使用方法及配置authorized_keys两台linux机器相互认证

Localdatetime

根据指定日期/时间创建对象 LocalDate localDate LocalDate.of(2018, 1, 13); LocalTime localTime LocalTime.of(9, 43, 20); LocalDateTime localDateTime LocalDateTime.of(2018, 1, 13, 9, 43, 20); System.out.println(localDate); System.out.println(localTime); Sy…

幸运抽奖案例

package xinyunchoujiang;import java.util.Scanner;/*** * * 项目名称&#xff1a;19qn3 * 类名称&#xff1a;CaiDan * 类描述&#xff1a; 幸运抽奖 * 创建人&#xff1a;Mu Xiongxiong * 创建时间&#xff1a;2020-4-2 下午5:13:15 * 修改人&#xff1a;…

基于OAuth2的认证(译)

OAuth 2.0 规范定义了一个授权&#xff08;delegation&#xff09;协议&#xff0c;对于使用Web的应用程序和API在网络上传递授权决策非常有用。OAuth被用在各钟各样的应用程序中&#xff0c;包括提供用户认证的机制。这导致许多的开发者和API提供者得出一个OAuth本身是一个认证…

Java 面试就业指导,100 % 提高面试成功率

转载自 Java 面试就业指导&#xff0c;100 &#xff05; 提高面试成功率 想要成为合格的Java程序员或工程师到底需要具备哪些专业技能&#xff0c;面试者在面试之前到底需要准备哪些东西呢&#xff1f; 本文陈列的这些内容既可以作为个人简历中的内容&#xff0c;也可以作为…