架构师_程序员

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

[.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382
[.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382
[.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382
[.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382
[.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382
[.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382
[.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382 [.Net/C#]2000人开发交流Qq群:348041382
查看: 161|回复: 1

[资料] 详解C# Tuple VS ValueTuple(元组类 VS 值元组)

[复制链接]
发表于 2018-5-14 16:37:48 | 显示全部楼层 |阅读模式
C# 7.0已经出来一段时间了,大家都知道新特性里面有个对元组的优化:ValueTuple。这里利用详尽的例子详解Tuple VS ValueTuple(元组类VS值元组),10分钟让你更了解ValueTuple的好处和用法。

如果您对Tuple足够了解,可以直接跳过章节”回顾Tuple”,直达章节”ValueTuple详解”,查看值元组的炫丽用法。

QQ截图20180514162917.jpg

回顾Tuple

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

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

元组的具体使用如下:

1.    如何创建元组

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

利用构造函数创建元组:

  1. var testTuple6 = new Tuple<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
  2. Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");

  3. 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));
  4. Console.WriteLine($"Item 1: {testTuple10.Item1}, Item 10: {testTuple10.Rest.Item3}");
复制代码
利用Tuple静态方法构建元组,最多支持八个元素:
  1. var testTuple6 = Tuple.Create<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
  2. Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");

  3. var testTuple8 = Tuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
  4. 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.    表示一组数据
如下创建一个元组表示一个学生的三个信息:名字、年龄和身高,而不用单独额外创建一个类。

  1. var studentInfo = Tuple.Create<string, int, uint>("Bob", 28, 175);
  2. Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
复制代码
3.    从方法返回多个值
当一个函数需要返回多个值的时候,一般情况下可以使用out参数,这里可以用元组代替out实现返回多个值。
  1. static Tuple<string, int, uint> GetStudentInfo(string name)
  2. {
  3.     return new Tuple<string, int, uint>("Bob", 28, 175);
  4. }

  5. static void RunTest()
  6. {
  7.     var studentInfo = GetStudentInfo("Bob");
  8.     Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
  9. }
复制代码
4.    用于单参数方法的多值传递

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

  1. static void WriteStudentInfo(Object student)
  2. {
  3.     var studentInfo = student as Tuple<string, int, uint>;
  4.     Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
  5. }

  6. static void RunTest()
  7. {
  8.     var t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(WriteStudentInfo));
  9.     t.Start(new Tuple<string, int, uint>("Bob", 28, 175));
  10.     while (t.IsAlive)
  11.     {
  12.         System.Threading.Thread.Sleep(50);
  13.     }
  14. }
复制代码
尽管元组有上述方便使用的方法,但是它也有明显的不足:

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


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

ValueTuple详解

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

ValueTuple 不需4.7,只要nuget就可以了,4.7是内置了。
另外ValueTuple是结构类型,微软建议超过64字节不要使用结构,对ValueTuple 同样有效。


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

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

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

利用构造函数创建元组:

  1. var testTuple6 = new ValueTuple<int, int, int, int, int, int>(1, 2, 3, 4, 5, 6);
  2. Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}");

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

  3. var testTuple8 = ValueTuple.Create<int, int, int, int, int, int, int, int>(1, 2, 3, 4, 5, 6, 7, 8);
  4. 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来访问。
  1. 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));
  2. Console.WriteLine($"Item 10: {testTuple10.Rest.Item3}, Item 10: {testTuple10.Item10}");
复制代码
2.    表示一组数据
如下创建一个值元组表示一个学生的三个信息:名字、年龄和身高,而不用单独额外创建一个类。
  1. var studentInfo = ValueTuple.Create<string, int, uint>("Bob", 28, 175);
  2. Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
复制代码
3.    从方法返回多个值
值元组也可以在函数定义中代替out参数返回多个值。
  1. static ValueTuple<string, int, uint> GetStudentInfo(string name)
  2. {
  3.     return new ValueTuple <string, int, uint>("Bob", 28, 175);
  4. }

  5. static void RunTest()
  6. {
  7.     var studentInfo = GetStudentInfo("Bob");
  8.     Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
  9. }
复制代码
优化区别:返回值可以不明显指定ValueTuple,使用新语法(,,)代替,如(string, int, uint):
  1. static (string, int, uint) GetStudentInfo1(string name)
  2. {
  3.     return ("Bob", 28, 175);
  4. }

  5. static void RunTest1()
  6. {
  7.     var studentInfo = GetStudentInfo1("Bob");
  8.     Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
  9. }
复制代码
调试查看studentInfo的类型就是ValueType三元组。

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

  1. static (string name, int age, uint height) GetStudentInfo1(string name)
  2. {
  3.     return ("Bob", 28, 175);
  4. }

  5. static void RunTest1()
  6. {
  7.     var studentInfo = GetStudentInfo1("Bob");
  8.     Console.WriteLine($"Student Information: Name [{studentInfo.name}], Age [{studentInfo.age}], Height [{studentInfo.height}]");
  9. }
复制代码
方便记忆赋值:

QQ截图20180514163532.jpg

4.    用于单参数方法的多值传递
当函数参数仅是一个Object类型时,可以使用值元组实现传递多个值。
  1. static void WriteStudentInfo(Object student)
  2. {
  3.     var studentInfo = (ValueTuple<string, int, uint>)student;
  4.     Console.WriteLine($"Student Information: Name [{studentInfo.Item1}], Age [{studentInfo.Item2}], Height [{studentInfo.Item3}]");
  5. }

  6. static void RunTest()
  7. {
  8.     var t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(WriteStudentInfo));
  9.     t.Start(new ValueTuple<string, int, uint>("Bob", 28, 175));
  10.     while (t.IsAlive)
  11.     {
  12.         System.Threading.Thread.Sleep(50);
  13.     }
  14. }
复制代码
5.    解构ValueTuple
可以通过var (x, y)或者(var x, var y)来解析值元组元素构造局部变量,同时可以使用符号”_”来忽略不需要的元素。
  1. static (string name, int age, uint height) GetStudentInfo1(string name)
  2. {
  3.     return ("Bob", 28, 175);
  4. }

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

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

  11.     var (_, age2, _) = GetStudentInfo1("Bob");
  12.     Console.WriteLine($"Student Information: Age [{age2}]");
  13. }
复制代码
由上所述,ValueTuple使C#变得更简单易用。较Tuple相比主要好处如下:

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





上一篇:大型架构之科普工具篇
下一篇:华为云发布区块链白皮书 加速区块链技术行业落地
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
发表于 2018-5-15 11:41:00 | 显示全部楼层
我很赞同!
码农网,只发表在实践过程中,遇到的技术难题,不误导他人。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

免责声明:
码农网所发布的一切软件、编程资料或者文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。

Mail To:help@itsvse.com

QQ|Archiver|手机版|小黑屋|架构师 ( 鲁ICP备14021824号-2 )|网站地图

GMT+8, 2018-5-28 07:29

Powered by Discuz! X3.4

© 2001-2014 Comsenz Inc.

快速回复 返回顶部 返回列表