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. Wannafly Winter Camp 2020 Day 6I 变大! - dp

    给定一个序列,可以执行 \(k\) 次操作,每次选择连续的三个位置,将他们都变成他们的最大值,最大化 \(\sum a_i\) 需要对每一个 \(k=i\) 输出答案 \(n \leq 50, a_i ...

  2. 使用nginx代理gogs遇到推送代码错误的问题(RPC failed; HTTP 413 curl 22 The requested URL returned error: 413)

    前提 代码管理我是用Gogs.Git,前些阵子使用Nginx将git.balabiu.com反向代理到了Gogs的默认端口,其他二级域名准备做其他使用, 导致上报代码出现了错误. 问题 推送代码报错误 ...

  3. gulp常用插件之gulp-uglify使用

    更多gulp常用插件使用请访问:gulp常用插件汇总 gulp-uglify这是一款使用UglifyJS缩小js文件. 更多使用文档请点击访问gulp-uglify工具官网. 安装 一键安装不多解释 ...

  4. CF1299D Around the World

    题意 \(n\)阶无向图,\(m\)条带权边,保证\(1\)不会被"超过\(3\)阶的圈"所包含.求删除与\(1\)相邻的边集,使得不存在从\(1\)出发的权值为\(0\)的非平凡 ...

  5. C++ const char *返回值问题

    今天写代码,遇到一个const char *返回值的问题,记录一下 问题场景:我写了一个动态库,有个函数声明如下: ; 函数定义如下: const char * HttpRequestImpl::RG ...

  6. vue中封装jsonp

    一.安装jsonp 二.封装

  7. ECMAScript规范中第六大基本类型 Symbol

    初步了解第六大基本类型Symbol 概述: 什么是Symbol.Symbol是一个标记,一个独一无二的记号. Symbol的出现主要是解决了以前ES5中两个问题 在属性中同名的属性会被覆盖 无法做到属 ...

  8. react-路由和Ant design

    路由的使用 react-router import React from 'react' // 如果要使用 路由模块,第一步,运行 yarn add react-router-dom // 第二步,导 ...

  9. Udacity_deep_learning_anconda

    1.创建anconda的虚拟环境: conda create -n your_env_name Python=X.X(2.7.3.6等) 2.查看anconda 有哪些虚拟环境: conda env ...

  10. 题解【洛谷P2264】情书

    题面 看到每一单词在同一句话中出现多次感动值不叠加,一眼想到 \(\text{set}\). 首先将词汇列表中的单词存储起来,我用的是 \(\text{set}\). 对于每一个句子的单词,我们可以先 ...