1. 老版本代码

 class Program
{
static void Main(string[] args)
{
var fullName = GetFullName(); Console.WriteLine(fullName.Item1);// Item1,2,3不能忍,,,
Console.WriteLine(fullName.Item2);
Console.WriteLine(fullName.Item3);
}
static Tuple<string, string, string> GetFullName() => new Tuple<string, string, string>("first name", "blackheart", "last name");
}

在有些场景下,我们需要一个方法返回一个以上的返回值,微软在.NET 4中引入了Tuple这个泛型类,可以允许我们返回多个参数,每个参数按照顺序被命名为 Item1;Item2,Item3 ,算是部分的解决了我们的问题,但是对于强迫症程序员来说,Item1,2,3的命名简直是不能忍的,,,so,在C#7中,引入了一个新的泛型类型ValueTuple<T>来解决这个问题,这个类型位于一个单独的dll(System.ValueTuple)中,可以通过nuget来引入到你当前的项目中(https://www.nuget.org/packages/System.ValueTuple/)。

2. ValueTuple

不废话,直接看代码:

 class Program
{
static void Main(string[] args)
{
var fullName = GetFullName(); Console.WriteLine(fullName.First); // 终于可以不是Item1,2,3了,,,
Console.WriteLine(fullName.Middle);
Console.WriteLine(fullName.Last);
} static (string First, string Middle, string Last) GetFullName() => ("first name", "blackheart", "last name");
}

看出来差别了吗?我们终于可以用更直观的名字来替换掉该死的"Item1,2,3"了,看起来很棒吧。但是貌似我们并没有用到上面我提到的System.ValueTuple,我们翻开编译后的程序集看看:

 internal class Program
{
private static void Main(string[] args)
{
ValueTuple<string, string, string> fullName = Program.GetFullName();
Console.WriteLine(fullName.Item1); // 原来你还是Item1,2,3,,,FUCK!!!
Console.WriteLine(fullName.Item2);
Console.WriteLine(fullName.Item3);
} [TupleElementNames(new string[]
{
"First",
"Middle",
"Last"
})]
private static ValueTuple<string, string, string> GetFullName()
{
return new ValueTuple<string, string, string>("first name", "blackheart", "last name");
}
}

不看不知道,一看吓一跳,原来我们的 fullName.First; 编译后居然还是 fullName.Item1 ,真是日了狗了。。。

不同之处在于GetFullName这个方法,编译器把我们简化的语法形式翻译成了 ValueTuple<string, string, string> ,还给加了一个新的Attribute(TupleElementNamesAttribute),然后把我们自定义的非常直观友好的“First”,"Middle","Last"当作元数据给存起来了(如果只是局部使用,则不会添加这样的元数据)。TupleElementNamesAttribute和ValueTuple一样,位于System.ValueTuple的单独dll中。

3. Example

 class Program
{
static void Main(string[] args)
{
var range = (first: , end: );
//也可以这样写,效果是一样的,编译后都是没有了first,end的痕迹,,,first和end只是语法层面的障眼法
//(int first, int last) range = (1, 10);
Console.WriteLine(range.first);
Console.WriteLine(range.end); //可以使用var,这种无显示声明一个变量的方式会编译出多余的代码,慎用,不知是不是还未优化好。
(var begin, var end) = (DateTime.Parse("2017-1-1"), DateTime.Parse("2017-12-31"));
Console.WriteLine(begin);
Console.WriteLine(end); //begin,end可以被覆盖重命名为startDate和endDate,但是会有一个编译警告,提示名字被忽略掉了。
//warning CS8123: The tuple element name 'begin' is ignored because a different name is specified by the target type '(DateTime startDate, DateTime endDate)'
//warning CS8123: The tuple element name 'end' is ignored because a different name is specified by the target type '(DateTime startDate, DateTime endDate)‘
(DateTime startDate, DateTime endDate) timeSpan = (begin: DateTime.Parse("2017-1-1"), end: DateTime.Parse("2017-12-31"));
Console.WriteLine(timeSpan.startDate);
Console.WriteLine(timeSpan.endDate);
}
}

look一下编译后的代码:

 private static void Main(string[] args)
{
ValueTuple<int, int> range = new ValueTuple<int, int>(, );
Console.WriteLine(range.Item1);
Console.WriteLine(range.Item2);
6 ValueTuple<DateTime, DateTime> expr_3C = new ValueTuple<DateTime, DateTime>(DateTime.Parse("2017-1-1"), DateTime.Parse("2017-12-31"));
7 DateTime item = expr_3C.Item1;
8 DateTime item2 = expr_3C.Item2;
9 DateTime begin = item;
10 DateTime end = item2;
Console.WriteLine(begin);
Console.WriteLine(end);
ValueTuple<DateTime, DateTime> timeSpan = new ValueTuple<DateTime, DateTime>(DateTime.Parse("2017-1-1"), DateTime.Parse("2017-12-31"));
Console.WriteLine(timeSpan.Item1);
Console.WriteLine(timeSpan.Item2);
}

注意 (var begin, var end) = (DateTime.Parse("2017-1-1"), DateTime.Parse("2017-12-31")); 这一行的便宜结果,看起来很是糟糕(上述6-10行红色部分),可能还是编译优化不足的问题吧(release编译也是如此)。

4. 总结

新的语法形式确实直观友好了好多,but,本质依然是借助泛型类型来实现的,同时也需要编译器对新语法形式的支持。

了解了本质是什么东西之后,以后在项目中环境允许的话,就放心大胆的使用吧(类型ValueTuple可以出现的地方,(first,last)这种新语法形式均可以)。

参考:

https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/

https://docs.microsoft.com/en-us/dotnet/articles/csharp/tuples

[C#7] 1.Tuples(元组)的更多相关文章

  1. 白话C#语法新特性之元组

    1.元组(Tuples) 元组(Tuple)在4.0 的时候就有了,但元组也有些缺点,如: 1)Tuple 会影响代码的可读性,因为它的属性名都是:Item1,Item2.. . 2)Tuple 还不 ...

  2. [Python] 03 - Lists, Dictionaries, Tuples, Set

    Lists 列表 一.基础知识 定义 >>> sList = list("hello") >>> sList ['h', 'e', 'l', ' ...

  3. swift语言的学习笔记

    swift参考了OC,Rust,Haskell,Ruby,Python,C#等语言的特性.首先,学习这门语言是速学的,我不想浪费太多时间在笔记这门语言和其他语言的哪里不同,特性你自己亲自实践就知道了. ...

  4. Swift-1-基本概念

    // Playground - noun: a place where people can play // 通过代码快速了解swift常用知识,需要一定object-c基础 import UIKit ...

  5. swift:入门知识之控制流

    1.swift语句中的控制流和其他语言大致相同,使用if和switch作为条件控制.使用 for-in.for.while.do-while作为循环. 2.区别之处:小括号不是必须的,但是主体的大括号 ...

  6. Swift流程控制之循环语句和判断语句详解

    Swift提供了所有c类语言的控制流结构.包括for和while循环来执行一个任务多次:if和switch语句来执行确定的条件下不同的分支的代码:break和continue关键字能将运行流程转到你代 ...

  7. [干货来袭]C#7.0新特性(VS2017可用)

    前言 微软昨天发布了新的VS 2017 ..随之而来的还有很多很多东西... .NET新版本 ASP.NET新版本...等等..太多..实在没消化.. 分享一下其实2016年12月就已经公布了的C#7 ...

  8. C#7.0新特性

    前言 微软昨天发布了新的VS 2017 ..随之而来的还有很多很多东西... .NET新版本 ASP.NET新版本...等等..太多..实在没消化.. 分享一下其实2016年12月就已经公布了的C#7 ...

  9. C#版本和.NET版本以及VS版本的对应关系

    C#版本和.NET版本以及VS版本的对应关系 版本 .NET Framework版本 Visual Studio版本 发布日期 特性 C# 1.0 .NET Framework 1.0 Visual ...

  10. Scala详解

    1       快速入门... 4 1.1             分号... 4 1.2             常变量声明... 4 1.2.1         val常量... 4 1.2.2  ...

随机推荐

  1. 浅谈Java工具类CommonUtils的使用

    package com.xushouwei.cn; import java.util.HashMap; import java.util.Map; import org.junit.Test; imp ...

  2. 日期、时间选择器(DatePicker和TimePicker)的功能与用法

    DatePicker和TimePicker是两个比较易用的控件,它们都从FrameLayout派生而来,其中DatePicker供用户选择日期:而TimePicker则供用户选择时间. DatePic ...

  3. KingbaseES的HA搭建

    1.配置资源前准备: 安装好数据库并保持两台机器用户ID及组ID一致,组ID和用户ID在/etc/passwd查看,如不保持一致,可能导致切机时阵列的属主改变,导致数据库无法启动. 建议用法,现在两台 ...

  4. CRtmpServer分析与应用

    CRtmpServer分析与应用 官方地址:http://www.rtmpd.com/ CRtmpServer是一款不错的开源流媒体服务器,用c++语言编写,跨平台.官方介绍CRtmpServer不仅 ...

  5. Redis key 相关命令

    其实本质上,Redis 就是一个Key---Value 数据库.这里我先介绍下Redis中关于的key的相关命令, 注意:key是字符串存储,但是不能使用 空格 或者 “\n”,value 则可以使用 ...

  6. 无限“递归”的python程序

    如果一个函数直接或者间接调用了自己,那么就形成了递归(recursion),比如斐波那契数列的一个实现 def fib(n): if n <= 2: return 1 else: return ...

  7. swift注意

    赋值的时候要想为空 可以用   ? 例如 var age1:Int? // ?表示age1的类型为可选类型,其值可以为空print(age1) 判断一个字符串为空字符串if str_empty.isE ...

  8. 西瓜书概念整理(chapter 1-2)

    括号表示概念出现的其他页码, 如有兴趣协同整理,请到issue中认领章节 完整版见我的github:ahangchen 觉得还不错的话可以点个star ^_^ 第一章 绪论 Page2: 标记(lab ...

  9. tomcat启动异常、和web.xml缺少配置异常

    错误如下: 14-Feb-2017 10:50:00.665 SEVERE [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.Sta ...

  10. docker - 容器里安装mysql

    在docker中安装mysql ubuntu官方镜像是精简的ubuntu系统,很多软件和库没有安装,所以直接安装mysql的话依赖较多,建议直接从源码编译安装mysql 通过命令行安装 先启动一个容器 ...