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

原文:https://blogs.msdn.microsoft.com/mazhou/2017/05/26/c-7-series-part-1-value-tuples/

译文:

从今天开始,我将开始一个新的C# 7系列文章,介绍C# 7+的新语言特性。请注意,我说的不是C# 7.0,我说的是C# 7+,因为将会有一些小的版本(比如7.1、7.2)逐步引入新的特性(感谢Roslyn!),比如async Main和default literals。

Tuples

类System.Tuple提供了一种类型来表示类似属性包的键值对。当你想用一种数据结构来保存一个带有属性(元素)的对象,但又不想创建一个单独的类型的时候,你可以使用它。下面的代码展示了如何用它作为一个方法的返回值,这个返回值包含了学生姓名和年龄。

public Tuple<string, int> GetStudentInfo(string id)
{
// Search by ID and find the student.
return new Tuple<string, int>("Annie", );
}

可以看到,我返回了一个Tuple<string,int>的实例对象,它的第一个参数是name,第二个参数是age。之后,我们在代码中调用这个方法,像这样:

public void Test()
{
Tuple<string, int> info = GetStudentInfo("100-000-1000");
Console.WriteLine($"Name: {info.Item1}, Age: {info.Item2}");
}

你可以通过引用Item1和Item2来访问name和age。

Tuple类有一些明显的问题:

  • 您需要使用ItemX这样的形式来访问属性,这样的属性名可能对调用者来说没有什么含义,如果我们可以使用类似info.Nameinfo.Age这样的形式来访问会比info.Item1info.Item2更好。
  • 最多只能有8个属性。如果需要更多,最后一个类型参数必须是另一个元组。这使得语法非常难以理解。
  • Tuple是一种引用类型,不像其他基本类型(它们是大多数值类型),它分配在堆上,对于CPU密集型操作来说,它可能需要太多的对象创建/分配。

Value Tuples

C# 7.0引入了ValueTuple结构,它是Tuple对象的值类型表示。C#语言团队为这个值元组类型做了很多不错的事情,包括新的语法和许多特性(比如解构)。

下面是使用Value Tuples的重写版本,请注意,如果在你的项目中不能用ValueTuple类型,那你必须通过NuGet下载System.ValueTuple 4.3.0 NuGet包到你的项目。如果您使用的是.Net Framework 4.7或更高版本,或者.Net Standard Library 2.0或更高版本,你什么也不用做,ValueTuple已经包含在内了。

public (string, int) GetStudentInfo(string id)
{
// Search by ID and find the student.
return ("Annie", );
} public void Test()
{
(string, int) info = GetStudentInfo("100-000-1000");
Console.WriteLine($"Name: {info.Item1}, Age: {info.Item2}");
}

通过使用语法(),上面的代码得到了极大的简化。 
您甚至可以为ValueTuple中的每个元素指定一个名称,如下所示:

public (string name, int age) GetStudentInfo(string id)
{
// Search by ID and find the student.
return (name: "Annie", age: );
} public void Test()
{
(string name, int age) info = GetStudentInfo("100-000-1000");
Console.WriteLine($"Name: {info.name}, Age: {info.age}");
}

帅!现在你的元组对象中的元素有了好的元数据,那么你就不需要来回检查确认返回/访问元素的顺序是正确的了。

当您使用值元组时,Visual Studio IDE会给您提示。

Value Tuple 解构

你可以从值元组对象中解构元素,并访问局部变量。

// 解构使用 var (x, y) 语法,
// 或者 (var x, var y) 语法。
var (name, age) = GetStudentInfo("100-000-1000");
// 现在你有两个局部变量:name and age.
Console.WriteLine($"Name: {name}, Age: {age}");

如果只关心某些元素而不是所有元素,可以使用_关键字忽略局部变量。

var (name, _) = GetStudentInfo("100-000-1000");
// 现在你只有一个局部变量:name,值age被忽略了。
Console.WriteLine($"Name: {name}");

从Value Tuples到Tuples

类型System.TupleSystem.ValueTuple提供了一些扩展方法来帮助它们之间相互转换。

var valueTuple = (id: , name: "Annie", age: , dob: DateTime.Parse("1/1/1993"));
var tuple = valueTuple.ToTuple();

结论

ValueTuple使C#语言更现代,更易于使用简化的语法。它解决了许多Tuple的问题:

  • 值元组对象具有第一类语法支持,它简化了使用元组元素的代码。
  • 您可以用一个名称与值元组的元素相关联,从而获得一定程度的设计阶段和编译器阶段的代码验证。
    请注意,与元组元素相关联的名字不是一个运行时的元数据,即在运行时的实例值元组中不存在这样一个名称的属性/字段,属性的名称仍Item1、Item2等等,所有的元素名称仅存在设计和编译阶段。
  • 你现在可以通过使用解构和_关键字灵活地访问所有元组元素,或者其中的一部分。
  • 值元组类型是值类型,没有继承或其他特性,这意味着值元组具有更好的性能。

由于值元组元素的名称不是运行时的,所以在使用一些类库(如Newtonsoft)进行序列化时,必须小心使用元组类型。除非你更新过支持新元数据(TupleElementNameAttribute等)的类库,否则你会遇到bug。

系列文章:

[译]C# 7系列,Part 1: Value Tuples 值元组的更多相关文章

  1. [译]C# 7系列,Part 9: ref structs ref结构

    原文:https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-series-part-9-ref-structs/ 背景 在之前的文章中,我解释了 ...

  2. [译]C# 7系列,Part 8: in Parameters in参数

    原文:https://blogs.msdn.microsoft.com/mazhou/2018/01/08/c-7-series-part-8-in-parameters/ 背景 默认情况下,方法参数 ...

  3. [译]C# 7系列,Part 2: Async Main 异步Main方法

    原文:https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main/ 你大概知道,C#语言可以构建两种 ...

  4. [译]C# 7系列,Part 3: Default Literals 默认文本表达式

    原文:https://blogs.msdn.microsoft.com/mazhou/2017/06/06/c-7-series-part-3-default-literals/ C#的default ...

  5. [译]C# 7系列,Part 4: Discards 弃元

    原文:https://blogs.msdn.microsoft.com/mazhou/2017/06/27/c-7-series-part-4-discards/ 有时我们想要忽略一个方法返回的值,特 ...

  6. [译]C# 7系列,Part 5: private protected 访问修饰符

    原文:https://blogs.msdn.microsoft.com/mazhou/2017/10/05/c-7-series-part-5-private-protected/ C#有几个可访问性 ...

  7. [译]C# 7系列,Part 6: Read-only structs 只读结构

    原文:https://blogs.msdn.microsoft.com/mazhou/2017/11/21/c-7-series-part-6-read-only-structs/ 背景 在.NET世 ...

  8. [译]C# 7系列,Part 7: ref Returns ref返回结果

    原文:https://blogs.msdn.microsoft.com/mazhou/2017/12/12/c-7-series-part-7-ref-returns/ 背景 有两种方法可以将一个值传 ...

  9. [译]C# 7系列,Part 10: Span<T> and universal memory management Span<T>和统一内存管理

    原文:https://blogs.msdn.microsoft.com/mazhou/2018/03/25/c-7-series-part-10-spant-and-universal-memory- ...

随机推荐

  1. python3 之 判断字符串是否只为数字(isdigit()方法、isnumeric()方法)

    Isdigit()方法 - 检测字符串是否只由数字组成 语法:   str.isdigit() 参数: 无 返回值: 如果字符串只包含数字,则返回True,否则返回False. 实例: 以下实例展示了 ...

  2. Java多线程编程(5)--线程间通信

    一.等待与通知   某些情况下,程序要执行的操作需要满足一定的条件(下文统一将其称之为保护条件)才能执行.在单线程编程中,我们可以使用轮询的方式来实现,即频繁地判断是否满足保护条件,若不满足则继续判断 ...

  3. 解决Debina系统自动更新软件包的问题

    不知从何时开始,我的电脑每天开机连接上网络之后,不断的在下载数据,状态栏显示网速达到每秒1到2兆.开始我还不太在意,不过后来由于带宽全部被这种莫名其奥妙的下载占据了,我连网页都无否正常浏览了,所以我决 ...

  4. Spring Boot通过ImportBeanDefinitionRegistrar动态注入Bean

    在阅读Spring Boot源码时,看到Spring Boot中大量使用ImportBeanDefinitionRegistrar来实现Bean的动态注入.它是Spring中一个强大的扩展接口.本篇文 ...

  5. Spring Cloud Gateway - 路由法则

    1. After Route Predicate Factory 输入一个参数:时间,匹配该时间之后的请求,示例配置: spring: cloud: gateway: routes: - id: af ...

  6. 如何在VMware下通过挂载系统光盘搭建本地yum软件仓库

    1.打开自己VMware软件中的虚拟机 2.输入用户名root密码登陆进去 3.打开 应用程序----收藏-----终端 4.首先回到根目录,输入cd ..(中间有空格) 5.创建一个名称为swlaa ...

  7. Linux运维的第一周总结

    这个阶段主要学习 Linux 运维技术,包括 Linux 基本操作.Bash 编程.应用服务部署.数据库服务部署.日志管理.系统监控等. 第1周: Linux基础本周学习 Linux 基本操作.用户与 ...

  8. Spring Boot 最简单整合Shiro+JWT方式

    简介 目前RESTful大多都采用JWT来做授权校验,在Spring Boot 中可以采用Shiro和JWT来做简单的权限以及认证验证,在和Spring Boot集成的过程中碰到了不少坑.便结合自身以 ...

  9. Python如何爬取实时变化的WebSocket数据【华为云技术分享】

    一.前言 作为一名爬虫工程师,在工作中常常会遇到爬取实时数据的需求,比如体育赛事实时数据.股市实时数据或币圈实时变化的数据.如下图: Web 领域中,用于实现数据'实时'更新的手段有轮询和 WebSo ...

  10. 不服跑个分:ARM鲲鹏云服务器实战评测——华为云鲲鹏KC1实例 vs. 阿里云G5实例【华为云技术分享】

    原文链接:https://m.ithome.com/html/444828.htm 今年一月份,华为正式发布了鲲鹏920数据中心高性能处理器,该处理器兼容ARM架构,采用7纳米制造,最高支持64核,主 ...