重学c#系列——元组 [三十一]
前言
元组并不是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以上版本可用。
- 值元组也是一种数据结构,用于表示特定数量和元素序列,但是是和元组类不一样的,主要区别如下:
值元组是结构,是值类型,不是类,而元组(Tuple)是类,引用类型;值元组的数据成员是字段不是属性,所以建议小写。 - 值元组元素是可变的,不是只读的,也就是说可以改变值元组中的元素值;
优化:当构造出超过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#系列——元组 [三十一]的更多相关文章
- 重学c#系列——字典(十一)
前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...
- .net基础学java系列(三)徘徊反思
.net基础学java系列(三)徘徊反思 上一篇文章:.net基础学java系列(二)IDE 之 插件 这两天晚上看完了IDEA的教学视频:https://edu.51cto.com/course/1 ...
- 重学c#系列——对c#粗浅的认识(一)
前言 什么是c#呢? 首先你是如何读c#的呢?c sharp?或者c 井? 官方读法是:see sharp. 有没有发现开发多年,然后感觉名字不对. tip:为个人重新整理,如学习还是看官网,c# 文 ...
- 重学c#系列——c# 托管和非托管资源(三)
前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存 ...
- 重学c#系列——datetime 和 datetimeoffset[二十一]
前言 简单介绍一下datetime和 datetimeoffset. 正文 了解一个国家的文化,就要了解一个国家的历史. 要了解datetimeoffset,那么很有必要了解一下datetime. 表 ...
- 重学c#系列——异常续[异常注意事项](七)
前言 对上节异常的补充,也可以说是异常使用的注意事项. 正文 减少try catch的使用 前面提及到,如果一个方法没有实现该方法的效果,那么就应该抛出异常. 如果有约定那么可以按照约定,如果约定有歧 ...
- 重学数据结构系列之——平衡树之SB Tree(Size Blanced Tree)
学习来源:计蒜客 平衡树 1.定义 对于每一个结点.左右两个子树的高度差的绝对值不超过1,或者叫深度差不超过1 为什么会出现这样一种树呢? 假如我们依照1-n的顺序插入到二叉排序树中,那么二叉排序树就 ...
- 重学Golang系列(一): 深入理解 interface和reflect
前言 interface(即接口),是Go语言中一个重要的概念和知识点,而功能强大的reflect正是基于interface.本文即是对Go语言中的interface和reflect基础概念和用法的一 ...
- 重学c#系列——list(十二)
前言 简单介绍一下list. 正文 这里以list为介绍. private static readonly T[] s_emptyArray = new T[0]; public List() { t ...
- 重学ES系列之字符串方面的处理
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
随机推荐
- 使用python制作动图
利用python制作gif图 引言 当写文章时候,多张图片会影响排版,可以考虑制作gif图 准备 pip install imageio 代码 # This is a sample Python sc ...
- Hbase之权限控制
Hbase之权限控制 -- 只读权限 grant '{userName}','R','{namespaceName:tableName}' -- 写入权限 grant '{userName}','W' ...
- API接口笔记
1.基类 定义返回信息 protected $user; //用户表 protected $token; //用户token protected $isSuccess = FALSE; //状态是 ...
- 三、Kubernetes调度
一.Kubernetes调度 Scheduler 是 kubernetes 的调度器,主要的任务是把定义的 pod 分配到集群的节点上.听起来非常简单,但有很多要考虑的问题: 公平:如何保证每个节点都 ...
- vue-axios 输入参数获取数据的写法
<template> <div class="nav"> <input v-model="name" type="tex ...
- 常用到的read命令
记录一下. 几个简单参数介绍 read -p :显示提示信息 read -s :静默模式(Silent mode),不会在屏幕上显示输入的字符.当输入密码和其它确认信息的时候,这是很有必要的. rea ...
- java学习之spring基础
0x00前言 spring框架应用的是ioc模式,ioc模式是指控制反转模式,本质是你不去创建对象让spring框架给你创建对象你去使用对象.多种开发模式通过配置文件和注解的方式去开发的都很值得去学习 ...
- 两种方案实现Dubbo泛化调用
Dubbo的泛化调用是一个服务A在没有服务B的依赖,包的情况下,只知道服务B的服务名:服务的接口的全限定类名和方法名,以及参数,实现服务A调用服务B. 原文链接:http://blog.qiyuan. ...
- Arch Linux 的安装
Arch Linux 的安装 作者:Grey 原文地址: 博客园:Arch Linux 的安装 CSDN:Arch Linux 的安装 版本 Arch Linux:2022.07.01 VMware ...
- 2022春每日一题:Day 22
题目:[HAOI2008]糖果传递 光看题几乎没有思路,但是显然到最后每个人手中一定有 d=s/n个糖果(s为所有人糖果总和),不妨设2号给1号x2个糖果,3号给2号x3个.....1号给n号x1个, ...