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

来源:互联网 发布:sql sum函数分组求和 编辑:程序博客网 时间:2024/06/10 11:39

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,来自永远薰薰]

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 铃木小r烧整流器怎么办 厨师在厨房太热怎么办 被家长投诉体罚孩子怎么办 空腹彩超喝水了怎么办 鱼把厕.所堵了怎么办 螃蟹爬进厕所里怎么办 抄作业被老师发现怎么办 鱼把厕所堵了怎么办 刚憋尿上完厕所之后腹部很疼怎么办 小孩被老师投诉了家长怎么办 家长投诉被老师知道了怎么办 孩子上课不敢回答问题怎么办 孩子犯了错家长怎么办 错了不该错的题怎么办 不该错的题错了怎么办 小学生不爱写课堂作业怎么办 手被老师打肿了怎么办 老师反应孩子学习退步了怎么办 学护理的打屁股针怎么办 教师被投诉打学生怎么办 遇到内向的学生教师应该怎么办 教师遇到顽劣的学生怎么办 家长质疑老师的能力怎么办 和领导有冲突该怎么办 孩子叫也不听特别叛逆怎么办 孩子叛逆期不听妈妈的话怎么办 学生和老师反嘴怎么办? 两个月的宝宝不拉屎怎么办 老师受家长的气怎么办 家长故意在班级群里气老师怎么办 幼儿园阿姨体罚孩子家长该怎么办 学生钱丢了老师怎么办 胸肌一边大一边小怎么办 被爱的人抛弃了怎么办 深蹲以后腿疼怎么办 做完蹲起大腿疼怎么办 练腿之后腿疼怎么办 深蹲做完后腿疼怎么办 做完上下蹲腿疼怎么办 钓鱼子线长了怎么办 烤箱烤红薯没有锡纸怎么办