欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-22 14:25:09
Mark Zhou写了很不错的一系列介绍C# 7的文章,虽然是2年多年前发布的,不过对于不熟悉C# 7特性的同学来说,仍然有很高的阅读价值。 原文:https://blogs.msdn.microsoft.com/mazhou/2017/05/26/c-7-series-part-1-value-t ......

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

原文:

 

译文:

从今天开始,我将开始一个新的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会给您提示。

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

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

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。