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>(, , , , , );
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>>(, , , , , , , new Tuple<int, int, int>(, , ));
Console.WriteLine($"Item 1: {testTuple10.Item1}, Item 10: {testTuple10.Rest.Item3}");
  • 利用Tuple静态方法构建元组,最多支持八个元素:
var testTuple6 = Tuple.Create<int, int, int, int, int, int>(, , , , , );
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}"); var testTuple8 = Tuple.Create<int, int, int, int, int, int, int, int>(, , , , , , , );
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", , );
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", , );
}
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", , ));
while (t.IsAlive)
{
System.Threading.Thread.Sleep();
}
}

尽管元组有上述方便使用的方法,但是它也有明显的不足:

  • 访问元素的时候只能通过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>(, , , , , );
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>>(, , , , , , , new ValueTuple <int, int, int>(, , ));
Console.WriteLine($"Item 1: {testTuple10.Item1}, Item 10: {testTuple10.Rest.Item3}");
  • 利用Tuple静态方法构建元组,最多支持八个元素:
var testTuple6 = ValueTuple.Create<int, int, int, int, int, int>(, , , , , );
Console.WriteLine($"Item 1: {testTuple6.Item1}, Item 6: {testTuple6.Item6}"); var testTuple8 = ValueTuple.Create<int, int, int, int, int, int, int, int>(, , , , , , , );
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>>(, , , , , , , new ValueTuple<int, int, int>(, , ));
Console.WriteLine($"Item 10: {testTuple10.Rest.Item3}, Item 10: {testTuple10.Item10}");

2.    表示一组数据

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

var studentInfo = ValueTuple.Create<string, int, uint>("Bob", , );
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", , );
}
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", , );
}
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", , );
}
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", , ));
while (t.IsAlive)
{
System.Threading.Thread.Sleep();
}
}

5.    解构ValueTuple

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

static (string name, int age, uint height) GetStudentInfo1(string name)
{
return ("Bob", , );
} 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

C# 元组和值元组的更多相关文章

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

    C# 7.0已经出来一段时间了,大家都知道新特性里面有个对元组的优化,并且网上也有大量的介绍,这里利用详尽的例子详解Tuple VS ValueTuple(元组类VS值元组),10分钟让你更了解Val ...

  2. Tuple元组 、 ValueTuple 值元组详解

    Tuple元组 Tuple是C# 4.0时出的新特性,.Net Framework 4.0以上版本可用. 元组是一种数据结构,具有特定数量和元素序列,与数组不同,元祖中的元素可以不同的数据类型.比如设 ...

  3. [译]C# 7系列,Part 1: Value Tuples 值元组

    Mark Zhou写了很不错的一系列介绍C# 7的文章,虽然是2年多年前发布的,不过对于不熟悉C# 7特性的同学来说,仍然有很高的阅读价值. 原文:https://blogs.msdn.microso ...

  4. C#关键字扫盲——Tuple(元组类) 、ValueTuple(值元组)

    原文:C#关键字扫盲--Tuple(元组类) .ValueTuple(值元组) 版权声明:本文为博主原创文章,随意转载. https://blog.csdn.net/Michel4Liu/articl ...

  5. TCP/IP的四元组、五元组、七元组

    TCP/IP的四元组.五元组.七元组 四元组是: 源IP地址.目的IP地址.源端口.目的端口 五元组是: 源IP地址.目的IP地址.协议号.源端口.目的端口 七元组是: 源IP地址.目的IP地址.协议 ...

  6. 2. Swift元组|可选值|断言

    1. 元组英文名字 Tuple,将多个数据类型(任意类型)组合成一个数据,与c语言的中的机构体有几分相似,功能也是非常强大的,尤其是在定义请求参数,状态之类的地方经常用到. let http404Er ...

  7. 【C#新特性】不用out ref同时返回多个值-元组Tuple

    元组Tuple,它是一种固定成员的泛型集合 下面先看看官方的一个使用例子: 创建一个包含7个元素的Tuple数组 // Create a 7-tuple. , , , , , );// Display ...

  8. JavaScript 判断变量是否为空---三元运算,元组获取值-重组.map()。

    var from_days = getQueryString('from_days'); undefined {'from_days': (from_days) ? from_days : null} ...

  9. Python元组与字符串操作(9)——随机数、元组、命名元组

    随机数 import random #导入random模块 randint(a,b) 返回[a,b]之间的整数 random.randint(0,9) randrange([start],stop,[ ...

随机推荐

  1. 洛谷P1808 单词分类_NOI导刊2011提高(01) 字符串排序

    洛谷P1808 单词分类_NOI导刊2011提高(01) 题目描述 Oliver为了学好英语决定苦背单词,但很快他发现要直接记住杂乱无章的单词非常困难,他决定对单词进行分类. 两个单词可以分为一类当且 ...

  2. STL-list 链表

    #include <iostream> #include <list> using namespace std; int main() { // list可以在头部和尾部插入和 ...

  3. 关于牛客网C语言结构体位域(bit-fields)的一道题

    题目链接地址: https://www.nowcoder.com/questionTerminal/f4e20747a2dd4649bac0c028daa234f4 来源:牛客网 低地址字节 Byte ...

  4. es6转码和package.json中的配置

    在线实时转换 需要babel-register .babelrc中: { "presets": [ "es2015" ] } 项目中main.js配置: 前提是 ...

  5. UVA11732(Trie树)

    鸣谢https://blog.csdn.net/Baoli1008/article/details/4441936,基本都是抄的代码 #pragma GCC optimize(2) #include ...

  6. 工控安全-PLC指纹提取的几种方法

    前言:PLC为可编程逻辑控制器,采用S7协议.其硬件本身存在许多漏洞,可以利用kali里面的漏洞模块或者modbus工具对其进行攻击,甚至直接可以进行未授权访问,只要其开启对外网的端口服务,那么我们就 ...

  7. PAT (Advanced Level) Practice 1036 Boys vs Girls (25 分)

    This time you are asked to tell the difference between the lowest grade of all the male students and ...

  8. PTA 1003 Emergency

    问题描述 As an emergency rescue team leader of a city, you are given a special map of your country. The ...

  9. JavaScript 中的构造函数

    典型的面向对象编程语言(比如C++和Java),存在“类”(class)这个概念.所谓“类”就是对象的模板,对象就是“类”的实例.但是,在JavaScript语言的对象体系,不是基于“类”的,而是基于 ...

  10. C++->以读或写方式打开一个文件

    以读或写方式打开一个文件 #include<iostream.h>   //.h以C|非C标准引用库文件 #include<fstream.h> #include<std ...