深入理解C♯ 7.0中的Tuple特性

介绍

Tuple是异类对象的有序序列。 我们经常可以写出返回多个值的方法,所以我们需要创建一个包含多个数据元素的简单结构。 为了支持这些情况,Tuple 被添加到 C#。 Tuple 是包含多个字段用来表示数据成员的轻量级数据结构。

如果一个方法返回多个相同类型的数值,那么它可以将这些值存储在一个集合中并返回该集合。 但是如果一个方法需要返回多个不同类型的值呢,C# 提供了一些可选项,比如 Class / Struct,输出参数和 Tuple。

让我们创建一个示例。 我们有一个整数的集合,而且我们需要从这个集合中找出的最小值和最大值。 这时候我们需要创建一个返回最小值和最大值的方法。 为了实现这一点,我们有三个选项:Class / Struct,输出参数和 Tuple。  那么,让我们逐个看看每个选项是如何完成这一功能的。

使用 out 参数

当我们创建一个方法,找出数字序列中的最大值和最小值。 该方法需要将两个值作为最大值和最小值的结果。 因此,我们创建返回值和使用 out 参数作为参数的方法。 返回值保存系列中的最大数,而 out 参数保存系列中的最小数。

让我们创建一个名为 Operation 的类,它实现一个从数字系列中查找最小和最大数的方法。 以下代码段就能实现该功能。

using System.Collections.Generic; 

namespace TupleApp
{
 class Operation
 {
 internal int FindMinMax(List<int> list, out int min)
 {
  int maximum = int.MinValue, minimum = int.MaxValue;
  list.ForEach(n =>
  {
  minimum = n < minimum ? n : minimum;
  maximum = n > maximum ? n : maximum;
  });
  min = minimum;
  return maximum;
 }
 }
}

根据上述代码片段,该方法返回一个值,该值保存一个名为 maximum 的整形变量。 该值是该系列的最大值。 此方法将输出参数是名为 min 的参数,该参数保存的是系列中的最小值。

现在,根据下面的代码片段从可执行程序调用此方法。

using System;
using System.Collections.Generic;
using System.Linq;
using static System.Console; 

namespace TupleApp
{
 class Program
 {
 static void Main(string[] args)
 {
  List<int> numbers = Enumerable.Range(1, 100).OrderBy(x => Guid.NewGuid()).Take(10).ToList();
  int minimum = 0, maximum = 0;
  Operation operation = new Operation();
  maximum = operation.FindMinMax(numbers, out minimum);
  Write($"{minimum} is min and {maximum} is max in {String.Join(",", numbers)}");
  Read();
 }
 }
}

现在,运行应用程序。 结果如下图所示。

图1:输出

这是正确的方法,但 out 参数并不适合于异步方法。

使用 Class/Struct

还有另一个选项可以从一个方法获取多个值–创建一个具有该数据结构的类或结构体。 我们在这里也执行相同的操作。 我们创建一个名为 CalculateData 的结构体,这个结构体中有两个属性来保存一个系列的最大值和最小值。 以下代码段就是用来创建这个结构体。

namespace TupleApp
{
 struct CalculateData
 {
 public int Minimum { get; set; }
 public int Maximum { get; set; }
 }
}

现在,让我们创建另一个名为 Operation 的类,它用来实现从数字序列中查找最小值和最大值的方法。 以下代码段就是用来实现这一功能。

using System.Collections.Generic; 

namespace TupleApp
{
 class Operation
 {
 internal CalculateData FindMinMax(List<int> list)
 {
  int maximum = int.MinValue, minimum = int.MaxValue;
  list.ForEach(n =>
  {
  minimum = n < minimum ? n : minimum;
  maximum = n > maximum ? n : maximum;
  });
  CalculateData data = new CalculateData
  {
  Minimum = minimum,
  Maximum = maximum
  };
  return data;
 }
 }
}

根据上面的代码片段,该方法返回一个具有两个属性的对象。 这些属性里保存的是系列中的最大值和最小值。
现在,从可执行程序调用此方法,如下面的代码片段所示。

using System;
using System.Collections.Generic;
using System.Linq;
using static System.Console; 

namespace TupleApp
{
 class Program
 {
 static void Main(string[] args)
 {
  List<int> numbers = Enumerable.Range(1, 100).OrderBy(x => Guid.NewGuid()).Take(10).ToList();
  Operation operation = new Operation();
  CalculateData data = operation.FindMinMax(numbers);
  Write($"{data.Minimum} is min and {data.Maximum} is max in {String.Join(",", numbers)}");
  Read();
 }
 }
}

现在,运行应用程序。 最终结果如下图所示。

图2: 输出结果

使用 Tuple

C#7 引入了定义元组的新方法。 Tuple 是从方法返回多个值的另一个选择。 它可以保存多个不同类型的值。 要在应用程序中使用 Tuple,我们需要安装 System.ValueTuple NuGet 包.

图3 NuGet 包

我们在这里也执行相同的操作。 让我们创建一个名为 Operation 的类,它实现一个从数字系列中查找最小值和最大数的方法。 以下代码段用来实现该功能。

using System.Collections.Generic; 

namespace TupleApp
{
 class Operation
 {
  internal (int, int) FindMinMax(List<int> list)
  {
   int maximum = int.MinValue, minimum = int.MaxValue;
   list.ForEach(n =>
   {
    minimum = n < minimum ? n : minimum;
    maximum = n > maximum ? n : maximum;
   });
   return (minimum, maximum);
  }
 }
}

根据上面的代码片段,该方法返回一个有两个项目的元组。 这些项目保存数字系列的最大值和最小值。

现在,根据下面的代码片段在可执行程序调用这个方法。

using System;
using System.Collections.Generic;
using System.Linq;
using static System.Console; 

namespace TupleApp
{
 class Program
 {
  static void Main(string[] args)
  {
   List<int> numbers = Enumerable.Range(1, 100).OrderBy(x => Guid.NewGuid()).Take(10).ToList();
   Operation operation = new Operation();
   (int, int) data = operation.FindMinMax(numbers);
   Write($"{data.Item1} is min and {data.Item2} is max from {String.Join(",", numbers)}");
   Read();
  }
 }
}

根据上面的代码片段,名为 FindMinMax 的方法调用并返回一个元组。 当方法直接返回多个值到一个 Tuple 类型,它们会按照他们的顺序给它们一些默认名称,以便可以方便地调用它们。这元组有两个项目,因此这些项目调用 Item1 和 Item2。 Item1 表示第一个值,而 Item2 表示第二个值。这跟 Tupple 项在创建时使用的顺序相同。

现在,运行应用程序。 最终结果如下图所示。

图4 输出结果

由于 Item1 和 Item2 不表示字段的实际名称,因此我们可以给它们自定义名称。 元组类型变量可以具有自定义名称,而不是仅仅是默认的 Item1 或 Item2。

让我们更新 Operation 类中名为 FindMinMax 的现有方法。 我们为这些元组字段分配自定义名称。 以下代码段用来实现该功能。

using System.Collections.Generic; 

namespace TupleApp
{
 class Operation
 {
  internal (int Minimum, int Maximum) FindMinMax(List<int> list)
  {
   int maximum = int.MinValue, minimum = int.MaxValue;
   list.ForEach(n =>
   {
    minimum = n < minimum ? n : minimum;
    maximum = n > maximum ? n : maximum;
   });
   return (minimum, maximum);
  }
 }
}

这里,元组的第一个字段名称为 Minimum,而另一个字段名为 Maximum。

现在,根据下面的代码片段从可执行程序调用此方法。

using System;
using System.Collections.Generic;
using System.Linq;
using static System.Console; 

namespace TupleApp
{
 class Program
 {
  static void Main(string[] args)
  {
   List<int> numbers = Enumerable.Range(1, 100).OrderBy(x => Guid.NewGuid()).Take(10).ToList();
   Operation operation = new Operation();
   var data = operation.FindMinMax(numbers);
   Write($"{data.Minimum} is min and {data.Maximum} is max from {String.Join(",", numbers)}");
   Read();
  }
 }
}

名为 FindMinMax 的方法调用并返回一个元组。 该元组有两个项目,根据元组项目的顺序称为最小值和最大值。

现在,运行应用程序并查看结果。

图5 输出结果

结论

Tuple 是异类对象的有序序列。 当一个方法需要返回多个值的时候使用它。Tuple 实例的条目数是固定的。Tuple 有最大数目为 8 项的限制。 如果我们想创建一个带有更多项的 Tuple,我们必须创建嵌套的 Tuple。 Tuple 的第八项必须是另一个 Tuple。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • C# 7.0 新特性1之基于Tuple的“多”返回值方法

    原文链接:http://www.cnblogs.com/ylvict/p/5573094.html 回顾  首先,提出一个问题,C#中,如何使一个方法可返回"多个"返回值?  我们先来回顾一下C#6.0 及更早版本的做法.   在C#中,通常我们有以下4种方式使一个方法返回多条数据. •使用 KeyValue 组合 • static void Main(string[] args) { int int1 = 15; int int2 = 25; var result = Add_Mul

  • 深入理解C♯ 7.0中的Tuple特性

    介绍 Tuple是异类对象的有序序列. 我们经常可以写出返回多个值的方法,所以我们需要创建一个包含多个数据元素的简单结构. 为了支持这些情况,Tuple 被添加到 C#. Tuple 是包含多个字段用来表示数据成员的轻量级数据结构. 如果一个方法返回多个相同类型的数值,那么它可以将这些值存储在一个集合中并返回该集合. 但是如果一个方法需要返回多个不同类型的值呢,C# 提供了一些可选项,比如 Class / Struct,输出参数和 Tuple. 让我们创建一个示例. 我们有一个整数的集合,而且我

  • 深入理解Android 5.0中的Toolbar

    环境说明: Android Studio 2.0 V7包版本:com.android.support:appcompat-v7:23.4.0 compileSdkVersion 23 buildToolsVersion "24.0.0" Toolbar 引入使用 XML布局中加入: <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="ma

  • 聊一聊C# 8.0中的await foreach使用

    AsyncStreamsInCShaper8.0 很开心今天能与大家一起聊聊C# 8.0中的新特性-Async Streams,一般人通常看到这个词表情是这样. 简单说,其实就是C# 8.0中支持await foreach. 或者说,C# 8.0中支持异步返回枚举类型async Task<IEnumerable<T>>. 好吧,还不懂?Good,这篇文章就是为你写的,看完这篇文章,你就能明白它的神奇之处了. 为什么写这篇文章 Async Streams这个功能已经发布很久了,在去年

  • C#7.0中新特性汇总

    以下将是 C# 7.0 中所有计划的语言特性的描述.随着 Visual Studio "15" Preview 4 版本的发布,这些特性中的大部分将活跃起来.现在是时候来展示这些特性,你也告诉借此告诉我们你的想法! C#7.0 增加了许多新功能,并专注于数据消费,简化代码和性能的改善.或许最大的特性就是元祖和模式匹配,元祖可以很容易地拥有多个返回结果,而模型匹配可以根据数据的"形"的不同来简化代码.我们希望,将它们结合起来,从而使你的代码更加简洁高效,也可以使你更加

  • C#3.0中Lambda表达式详解

    在C#2.0中,微软给我们带来了一些新的特性,例如泛型,匿名委托等.然而,这些新的特性多多少少会给人一种从别的语言中"抄"来的感觉(例如泛型类似C++的模板,一些特性类似Java中的一些东西).但是在C#3.0中,微软给我带来的一些新特性可能是以前所有开发语言都没有的特性.这无疑大大的体现了C#3.0在开发语言中强大的优势. Lambda表达式 Lambda 表达式是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型.所有 Lambda 表达式都使用 Lambd

  • Android Studio 3.0中mipmap-anydpi-v26是什么东东

    在Android Studio 3.0中一旦我们创建了一个项目,一个名为mipmap-anydpi-v26自动创建的文件夹在res文件夹下.它究竟能干什么?为什么我们需要这个?我们在开发时该如何利用它? 另外,在项目创建之后,还会在此文件夹中创建两个xml文件.为什么这些文件在mipmap文件夹中?根据我们的理解,所有xml文件是保存在drawable目录下而不是mipmap中的. Android Studio 3.0会为您的应用程序创建一个自适应图标,该图标仅在sdk 26中可用.启动图标应放

  • vue3.0中的双向数据绑定方法及优缺点

    熟悉vue的人都知道在vue2.x之前都是使用object.defineProperty来实现双向数据绑定的 而在vue3.0中这个方法被取代了 1. 为什么要替换Object.defineProperty 替换不是因为不好,是因为有更好的方法使用效率更高 Object.defineProperty的缺点: 1. 在Vue中,Object.defineProperty无法监控到数组下标的变化, 导致直接通过数组的下标给数组设置值,不能实时响应. push() pop() shift() unsh

  • 详解.NET Core 3.0中的新变化

    .NET Core 3.0 是 .NET Core 平台的下一主要版本.本文回顾了 .Net Core 发展历史,并展示了它是如何从基本支持 Web 和数据工作负载的版本 1,发展成为能够运行 Web.桌面.机器学习.容器.IoT 等的版本 3.0. .NET Core 1 .NET Core 的历史可追溯到几年前,版本 1 是在 2016 年推出,旨在生成第一版开放源代码和跨平台(Windows.macOS 和 Linux)的 .NET.灵感来源于只能使用开放源代码框架的客户,以及需要在 Li

  • vue2.0 中使用transition实现动画效果使用心得

    实践 这里将通过四个实践小案例来体验和学习css过渡,css动画,javascript钩子,列表过渡的应用.至于案例用到的知识点就请自行学习官网文档. 1.css过渡–实践 先来看看demo效果: 这个案例其实很简单,通过一个transition来触发多个子元素的过渡效果,我们只需要定义元素对应的过渡效果就可以,其他事情vue会帮我们搞定,由此可以扩展出其他酷炫的过渡场景效果.先来看看这个简单案例的代码实现: <template> <div class="app"&g

  • Pandas DataFrame中的tuple元素遍历的实现

    pandas中遍历dataframe的每一个元素 假如有一个需求场景需要遍历一个csv或excel中的每一个元素,判断这个元素是否含有某个关键字 那么可以用python的pandas库来实现. 方法一: pandas的dataframe有一个很好用的函数applymap,它可以把某个函数应用到dataframe的每一个元素上,而且比常规的for循环去遍历每个元素要快很多.如下是相关代码: import pandas as pd data = [["str","ewt"

随机推荐