前言

元组并不是c# 7.0的东西,早之前就有,叫做tuple。7.0加了valuetuple。

来看下元组吧,主要一些注意的地方。

正文

为什么在7.0 之前,元组用的不多呢?

因为tuple 在代码优雅上和阅读上存在很大的问题,因为有匿名类型,是一个鸡肋的存在。

Tuple,翻译过来是元组的意思,元组听到这个词,一般会想到两个特性,一个是不可扩展,一个是顺序已定。

这种的确灵活性不高,这并不是一个贬义词。灵活性不高表示其稳定。

static void Main(string[] args)
{
Tuple<int, int> a = Tuple.Create(1, 2);
var b= a.Item1;
var c = a.Item2; Console.ReadKey();
}

当看到这个代码的第一眼,是不是有一种坏味道的感觉?

理由也很简单,a.Item1 含义是什么,这是调用者费解的问题。

这里完全可以用匿名类型替换。

那么是否匿名类型是否能完全替代元组呢?不能。

public static Tuple<int, int> Divide (int dividend, int divisor)
{
int result = dividend / divisor;
int remainder = dividend % divisor; return Tuple.Create( result, remainder );
}

因为元组可以作为方法的返回值。所以元组在内部方法的时候还是可以用一下的(因为内部更能知道其具体的实现目标),不用声明新的模型,但是对胃不好。

像下面这样:

这样作为内部方法。那么如果放在方面会有什么感觉呢?感受一下。

那么就是main需要事先知道"外部"的信息,item1是name,item2是age。其他内调用的也需要知道,使用的成本就更高了。如果是public外部调用,那么味道就更重了。

前面提及到其稳定,那么其稳定表现到什么地方呢?

不能被修改。这并不是缺陷,相反这是一个特性。

因为元组不可修改,代表其稳定,当使用元组的时候就不用考虑其是否修改,这个在后面设计篇的时候会介绍下稳定性的好处。

简单看下create,其还是可以嵌套元组的。

不用纠结太多,在7.0之前元组基本只有这点用处。地位有点尴尬,感觉像是对匿名类型的补充。

那么到了7.0之后呢? 增加了ValueTuple。

ValueTuple是C# 7.0的新特性之一,.Net Framework 4.7以上版本可用。

  1. 值元组也是一种数据结构,用于表示特定数量和元素序列,但是是和元组类不一样的,主要区别如下:

    值元组是结构,是值类型,不是类,而元组(Tuple)是类,引用类型;值元组的数据成员是字段不是属性,所以建议小写。
  2. 值元组元素是可变的,不是只读的,也就是说可以改变值元组中的元素值;

优化:当构造出超过7个元素以上的值元组后,可以使用接下来的ItemX进行访问嵌套元组中的值,对于上面的例子,要访问第十个元素,既可以通过testTuple10.Rest.Item3访问,也可以通过testTuple10.Item10来访问。

前面这个算不上优化的地方,因为一般不会超过7个,如果超过7个,那么其具备某种含义,应该建模,创建类。

关于4.6以下需要使用。 4.7内置,4.0以上NuGet能直接装System.ValueType包

前面其主要是诟病的地方是过于抽象(使用item1这种名称),第二个是创建繁琐,需要Tuple.create(),那么在这个版本就解决了这种问题。

static void Main(string[] args)
{
var student = GetStudentInfo1();
var age = student.age; Console.ReadKey();
} static (string name, int age, uint height) GetStudentInfo1()
{
return ("Bob", 28, 175);
}

不仅解决了创建和使用的问题,还增加了一些新的特性。

上面这种var student = GetStudentInfo1(),一般不建议这么写的。

因为(string name, int age, uint height)并不能代表student,这种学生模型。

元组是一些数值的组合,并不能替代模型。

static void Main(string[] args)
{
var (name, age, hight) = GetStudentInfo1(); Console.ReadKey();
} static (string name, int age, uint height) GetStudentInfo1()
{
return ("Bob", 28, 175);
}

写法上更希望是上面这种,表示的是一些数值的组合。

那么其设计也有弃元这个东西,因为可能只使用了其中的一部分。

internal class Program
{
static void Main(string[] args)
{
var (_, age, _) = GetStudentInfo1(); Console.ReadKey();
} static (string name, int age, uint height) GetStudentInfo1()
{
return ("Bob", 28, 175);
}
}

最后一个关键的点,那就是前面能实现这些:

static (string name, int age, uint height) GetStudentInfo1()
{
return ("Bob", 28, 175);
}
var (name, age, hight) = GetStudentInfo1();
var (_, age, _) = GetStudentInfo1();

统统都是语法糖。

并不是ValueTuple 这么强大,而是编译器工具强大了。

你发现跟原来区别不大:

然后其实这些name啊,age啊,height啊,在运行时候ValueTuple也没有。

他们在ValueTuple 还是item1,item2,item3。

var a = ("Bob", 28, 175);
var output =JsonConvert.SerializeObject(a); Console.WriteLine(output);
Console.ReadKey();

所以不要吧什么元组直接返回给ActionResult,那么得到的结果是item1,item2这种,因为编译后运行的时候调用就会把具体名称缓存item1和item2,这和匿名类型是不同的,匿名类型是编译会生成具体的类。

说一下在设计上值得注意的地方,就是元组应该是类内部使用。

为什么这么说呢?

因为成本问题,比如说:

static (string name, int age, uint height) GetStudentInfo1()
{
return ("Bob", 28, 175);
}

对于外部类来说,其实就是返回多个值,并没有具体的对象含义。

不像是下面这种:

static Student GetStudentInfo1()
{
return db.getStudent();
}

其最大的使用范围其实就是类的内部,内部方法是最佳场景,当然其在本身实现上没有限制。

因为这个元组有很多个人看法在里面,如有不对望请指出或者其他的不同想法也可以交流下。

重学c#系列——元组 [三十一]的更多相关文章

  1. 重学c#系列——字典(十一)

    前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...

  2. .net基础学java系列(三)徘徊反思

    .net基础学java系列(三)徘徊反思 上一篇文章:.net基础学java系列(二)IDE 之 插件 这两天晚上看完了IDEA的教学视频:https://edu.51cto.com/course/1 ...

  3. 重学c#系列——对c#粗浅的认识(一)

    前言 什么是c#呢? 首先你是如何读c#的呢?c sharp?或者c 井? 官方读法是:see sharp. 有没有发现开发多年,然后感觉名字不对. tip:为个人重新整理,如学习还是看官网,c# 文 ...

  4. 重学c#系列——c# 托管和非托管资源(三)

    前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存 ...

  5. 重学c#系列——datetime 和 datetimeoffset[二十一]

    前言 简单介绍一下datetime和 datetimeoffset. 正文 了解一个国家的文化,就要了解一个国家的历史. 要了解datetimeoffset,那么很有必要了解一下datetime. 表 ...

  6. 重学c#系列——异常续[异常注意事项](七)

    前言 对上节异常的补充,也可以说是异常使用的注意事项. 正文 减少try catch的使用 前面提及到,如果一个方法没有实现该方法的效果,那么就应该抛出异常. 如果有约定那么可以按照约定,如果约定有歧 ...

  7. 重学数据结构系列之——平衡树之SB Tree(Size Blanced Tree)

    学习来源:计蒜客 平衡树 1.定义 对于每一个结点.左右两个子树的高度差的绝对值不超过1,或者叫深度差不超过1 为什么会出现这样一种树呢? 假如我们依照1-n的顺序插入到二叉排序树中,那么二叉排序树就 ...

  8. 重学Golang系列(一): 深入理解 interface和reflect

    前言 interface(即接口),是Go语言中一个重要的概念和知识点,而功能强大的reflect正是基于interface.本文即是对Go语言中的interface和reflect基础概念和用法的一 ...

  9. 重学c#系列——list(十二)

    前言 简单介绍一下list. 正文 这里以list为介绍. private static readonly T[] s_emptyArray = new T[0]; public List() { t ...

  10. 重学ES系列之字符串方面的处理

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. python续集

    上集回顾 数据类型内置方法简介 所有的数据类型基本上都自带了一些操作以及通过点的方式调用自带的方法 整型相关操作 类型转换 int() 十进制转其他进制 bin() oct() hex() 其他进制转 ...

  2. 基于docker安装phpmyadmin

    今天用到了phpadmin,要从头装的话,比较麻烦,所以就选择使用docker 安装 准备 任意Linux系统且已成功安装docker环境 安装phpmyAdmin 1. 拉取镜像 docker pu ...

  3. Oracle导出和导入

    导出 exp exp 用户名/密码@实例名 file=导出的dmp文件存放路径 l og=导出日志存放路径 exp hr/123456@orcl file= C:\Users\Administrato ...

  4. 驱动开发:内核特征码扫描PE代码段

    在笔者上一篇文章<驱动开发:内核特征码搜索函数封装>中为了定位特征的方便我们封装实现了一个可以传入数组实现的SearchSpecialCode定位函数,该定位函数其实还不能算的上简单,本章 ...

  5. 2022网刃杯ics

    ​ 目录 easyiec Ncsubj 喜欢移动的黑客 xyp07 ICS6-LED_BOOM 根据大佬的wp后,自己做了一遍 这次学到很多东西 ICS easyiec tcp追踪流直接能看到 ​编辑 ...

  6. 『现学现忘』Git基础 — 37、标签tag(二)

    目录 5.共享标签 6.删除标签 7.修改标签指定提交的代码 8.标签在.git目录中的位置 9.本文中所使用到的命令 提示:接上一篇文章内容. 5.共享标签 默认情况下,git push 命令并不会 ...

  7. 2.CBV和类视图as_view源码解析

    一.FBV和CBV # 视图基于函数开发 FBV: function.base.views # 视图基于类开发 CBV: class .base .views #Python是一个面向对象的编程语言, ...

  8. 分享几个关于Camera的坑

    最近忙于开发一款基于Camera2 API的相机应用,部分功能涉及到广角镜头,因此踩了不少坑,在此与大家分享下以作记录交流... 经过查阅资料发现在安卓上所谓的广角镜头切换其实是用一个逻辑摄像头包含多 ...

  9. Codeforces Global Round 23 A-D

    比赛链接 A 题解 知识点:贪心,构造. 注意到有 \(1\) 就一定能构造. 时间复杂度 \(O(n)\) 空间复杂度 \(O(1)\) 代码 #include <bits/stdc++.h& ...

  10. 【题解】CF631B Print Check

    题面传送门 解决思路: 首先考虑到,一个点最终的情况只有三种可能:不被染色,被行染色,被列染色. 若一个点同时被行.列染色多次,显示出的是最后一次被染色的结果.所以我们可以使用结构体,对每一行.每一列 ...