[译]C# 7系列,Part 1: Value Tuples

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", 25);
}

可以看到,我返回了一个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", 25);
}

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: 25);
}

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: 1, name: "Annie", age: 25, dob: DateTime.Parse("1/1/1993"));
var tuple = valueTuple.ToTuple();

结论

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

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

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

原文地址:https://www.cnblogs.com/wenhx/p/c-7-series-part-1-value-tuples.html

时间: 2024-10-20 20:05:46

[译]C# 7系列,Part 1: Value Tuples的相关文章

[译]C# 7系列,Part 2: Async Main

原文:https://blogs.msdn.microsoft.com/mazhou/2017/05/30/c-7-series-part-2-async-main/ 你大概知道,C#语言可以构建两种程序.一种是带有入口点(entrypoint)的程序,这样操作系统就可以加载程序并从入口点执行;另一个是没有入口点的程序.操作系统不能直接执行程序,程序可以被其他有入口点的程序引用,这样就可以执行其中的代码. 必须有入口点的应用程序类型有:Windows Forms应用程序.UWP应用程序.控制台应

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

原文:https://blogs.msdn.microsoft.com/mazhou/2017/10/05/c-7-series-part-5-private-protected/ C#有几个可访问性修饰符,public.internal.internal protected和private. public: 具有此可访问性声明的成员可以在此成员所在程序集中或引用该成员所在程序集的任何其他程序集中可见.也就是说,访问不受限制. internal:具有此可访问性声明的成员可以在此成员所在程序集中可

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

原文:https://blogs.msdn.microsoft.com/mazhou/2017/12/12/c-7-series-part-7-ref-returns/ 背景 有两种方法可以将一个值传递给一个方法: 按值传递.当一个参数被传递给一个方法时,一个参数的副本(如果它是一个值类型)或一个"参数引用"的副本(如果它是一个引用类型)被传递.当您更改方法中的参数时,更改(单个赋值或复合赋值)会反映到参数/"参数引用"的副本,而不会反映到参数或“参数引用”本身.这

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

原文:https://blogs.msdn.microsoft.com/mazhou/2018/01/08/c-7-series-part-8-in-parameters/ 背景 默认情况下,方法参数是通过值传递的.也就是说,参数被复制并传递到方法中.因此,修改方法体中的参数不会影响原始值.在大多数情况下,修改是不必要的. 其他编程语言,如C++,有一个const参数或类似的概念:这表明方法体中的参数是一个不能被重新赋值的常量.它有助于避免在方法体内无意中重新赋值一个方法参数的错误,并通过不允许

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

原文:https://blogs.msdn.microsoft.com/mazhou/2018/03/02/c-7-series-part-9-ref-structs/ 背景 在之前的文章中,我解释了许多新的C#特性,每一个特性都是为了增强语言或者解决问题而引入的.具体来说,我解释了值类型和引用类型.按值传递参数.按引用传递参数.ref局部变量和ref返回结果以及in参数.这其中许多功能是为高性能场景设计的. ref和in参数可以帮助避免复制值,从而减少内存分配.当你有分配在堆栈的局部变量作为方

[译]GC专家系列2:Java 垃圾回收的监控

原文链接:http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/ 这是"成为GC专家系列"文章的第二篇.在第一篇理解Java垃圾回收中我们学习了几种不同的GC算法的处理过程,GC的工作方式,新生代与老年代的区别.到目前为止,你应该已经了解了JDK 7中的5种GC类型,以及每种GC对性能的影响. 在本篇中,我将介绍JVM在真实环境中如何运行GC的. 什么是GC监控 GC监控 指的是在运

【译】STM32L4x6系列用户手册第四章 - 防火墙(FireWall)

4        防火墙(FW) 4.1        简介 防火墙用于保护非易失性存储器中的特定部分的代码或数据,和/或保护SRAM1中的易失性数据,免受在保护区域外部执行的其余代码的非法访问. 4.2        防火墙的主要功能 •        防火墙保护的代码(代码段)可能位于: –        Flash存储器 –        SRAM1存储器,如果在防火墙配置步骤中被声明为可执行保护区域. •        要保护的数据也可以位于 –        Flash存储器中(非易失

[译]GC专家系列1: 理解Java垃圾回收

原文链接:http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/ 了解Java的垃圾回收(GC)原理能给我们带来什么好处?对于软件工程师来说,满足技术好奇心可算是一个,但重要的是理解GC能帮忙我们更好的编写Java应用程序. 上面是我个人的主观的看法,但我相信熟练掌握GC是成为优秀Java程序员的必备技能.如果你对GC执行过程感兴趣,也许你只是有一定的开发应用的经验:如果你仔细考虑过如何选择合适

抽取公共代码

如果要彻底明白 Webpack V4 版本如何抽取公共代码,就要设计一个场景来支持抽取公共代码的多种形式,能够从代码运行的结果中查看实际的效果,从效果中深入理解各个参数的作用. 场景设计 在设计场景之前,首先要明白公共代码抽取常见的几种情况: 抽取 Webpack 运行时代码 直接加载的代码抽取(静态引入) node_modules 中的代码 项目中的业务代码 按需加载的代码抽取(动态引入) node_modules 中的代码 项目中的业务代码 经过分析会发现,现在常见的场景就五种,设计一个应用