title author date CreateTime categories
C# ValueTuple 原理
lindexi
2018-08-10 19:16:52 +0800
2018-2-13 17:23:3 +0800
C# 原理

本文告诉大家一些 ValueTuple 的原理,避免在使用出现和期望不相同的值。ValueTuple 是 C# 7 的语法糖,如果使用的 .net Framework 是 4.7 以前,那么需要使用 Nuget 安装System.ValueTuple

虽然 ValueTuple 的很好用,但是需要知道他有两个地方都是在用的时候需要知道他原理。如果不知道原理,可能就发现代码和预期不相同

json 转换

先创建一个项目,然后安装 Json 解析,使用下面的代码,在运行之前,先猜一下,下面的代码会出现什么

            var foo = (name: "lindexi", site: "blog.csdn.net/lindexi_gd");
var str = JsonConvert.SerializeObject(foo);

实际上输出的是 {"Item1":"lindexi","Item2":"blog.csdn.net/lindexi_gd"}

那么刚才的命名在哪?

如果想知道,那么请看 ValueTuple 的原理

原理

先来写一段代码,编译之后对他反编译,看一下他是怎么做的

        static void Main(string[] args)
{
var foo = Foo();
var str = JsonConvert.SerializeObject(foo);
Console.WriteLine(str);
} static (string name, string site) Foo()
{
return (name: "lindexi", site: "blog.csdn.net/lindexi_gd");
}

不需要安装反编译软件,可以使用这个网站拿到反编译

可以看到Foo被编译为 TupleElementNames 特性的两个字符串

    [return: TupleElementNames(new string[]
{
"name",
"site"
})]
private static ValueTuple<string, string> Foo()
{
return new ValueTuple<string, string>("lindexi", "blog.csdn.net/lindexi_gd");
}

所以实际上代码是 ValueTuple<string, string> 不是刚才定义的代码,只是通过 TupleElementNames 让编译器知道值,所以是语法糖。

IL 代码是

private hidebysig static valuetype [mscorlib]System.ValueTuple`2<string, string>
Foo() cil managed
{
.param [0]
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[])
= (
01 00 02 00 00 00 04 6e 61 6d 65 04 73 69 74 65 // .......name.site 这里就是 return: TupleElementNames 的命名
00 00 // ..
)
.maxstack 2
.locals init (
[0] valuetype [mscorlib]System.ValueTuple`2<string, string> V_0
) // [20 9 - 20 10]
IL_0000: nop // [21 13 - 21 72]
IL_0001: ldstr "lindexi"
IL_0006: ldstr "blog.csdn.net/lindexi_gd"
IL_000b: newobj instance void valuetype [mscorlib]System.ValueTuple`2<string, string>::.ctor(!0/*string*/, !1/*string*/)
IL_0010: stloc.0 // V_0
IL_0011: br.s IL_0013 // [22 9 - 22 10]
IL_0013: ldloc.0 // V_0
IL_0014: ret }

这个特性只有编译器可以用,不可以在代码使用。

在上面的解释,实际上 IL 不知道存在定义的命名,所以不可以通过这个方法获得值。

动态类型获得值

如果希望使用动态类型获得值,那么下面的代码实际上会运行出现异常

        static void Main(string[] args)
{
dynamic foo = Foo();
Console.WriteLine(foo.name);
} static (string name, string site) Foo()
{
return (name: "lindexi", site: "blog.csdn.net/lindexi_gd");
}

运行出现 RuntimeBinderException 异常,因为没有发现 name 属性

实际上对比下面匿名类,也就是很差不多写法。

        dynamic foo = new { name = "lindexi", site = "blog.csdn.net/lindexi_gd" };
Console.WriteLine(foo.name);

运行是可以的,所以在使用动态类型,请不要使用 ValueTuple ,如果需要使用,那么请知道有存在找不到变量异常,而且是在运行才出现异常。

性能提升

如果使用 ValueTuple 编程会有一些优点,性能是其中之一。而且对于异步编程,使用 ValueTuple 可以继续使用 await 的方法。

假如有一个方法需要返回 5 个参数,那么以前的做法有三个方法,第一个方法是使用 out 的方法,第二个方法是使用 Tuple ,第三个方法是定义一个临时的类。

如果使用了 out 的方法,那么这个方法就不可以继续使用异步 await 的方法,因为 await 需要做出状态机,参见我写的await原理。如果使用 Tuple ,或这定义一个临时的类,就会出现性能的问题。

从上面的原理,已经告诉大家,ValueTuple 是值类型,而 Tuple 或定义的一个类不是值类型。编译器的优化是让 ValueTuple 分配在栈,对于普通的类分配在堆空间。如果一个类分配到堆空间,那么就需要使用垃圾回收才可以清理空间。而分配到栈就不需要使用垃圾回收,使用完成就清空栈,效率比堆空间大。

但是使用栈空间需要注意,栈空间是很小的,如果使用了大量栈空间可能会出现堆栈gg。因为考虑到部分刚入门的小伙伴,所以我就需要多说一些,上面说的 ValueTuple 使用了栈空间需要小心栈空间不足,和你存放的值的关系不大,而是和定义的 ValueTuple 数量有关,这个数量是非常大的。但是在递归方法中,本来是刚好空间足够的,在使用了 ValueTuple 可能就不够了。

使用 ValueTuple 可以继续使用异步,而且不需要垃圾回收,性能比Tuple高,所以建议在多返回参数使用 ValueTuple,而不是定义一个类。

其他需要知道的

不要随便定义一个看不懂的值

实际上下面的代码,编译是可以通过

(int x, (int y, (float a, float b))[] c) f1

但是这个值,在看的时候,几乎说不出他的属性

第二个需要知道的,ValueTuple 是值类型,所以他的默认值不是 null 而是 default(xx),在C# 7.2 支持使用关键字,所以不需要去写 defalut(xx,xx)

关于 ValueTuple 变量名的定义也是很难说的,有的小伙伴觉得需要使用 Axx 的方式命名,但是很多小伙伴觉得使用 aaBa 的命名更好,所以暂时对于他的命名使用 aaBa 的方法,大家觉得什么方式好请告诉我

参见:Exploring Tuples as a Library Author

C# 7: Dynamic types and Reflection cannot access Tuple fields by name

2018-8-10-C#-ValueTuple-原理的更多相关文章

  1. 申请Office 365一年免费的开发者账号攻略(2018年10月份版本)

    要进行Office 365开发,当然需要有完整的Office 365环境才可以.为了便于广大开发人员快速地启动这项工作,微软官方给所有开发人员提供了免费的一年开发者账号   那么如何申请Office ...

  2. IntelliJ IDEA 最新激活码(截止到2018年10月14日)

    IntelliJ IDEA 注册码: EB101IWSWD-eyJsaWNlbnNlSWQiOiJFQjEwMUlXU1dEIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYX ...

  3. 新手C#SQL Server使用记录2018.08.10

    主键(PrimaryKey):主键就是每个数据行(记录)的唯一标识,不会有重复值的列(字段)才能当做主键.一个表可以没有主键,但是这样会很难处理表,因此一般情况表都要设置主键. 主键有两张选用策略,分 ...

  4. 01 mybatis框架整体概况(2018.7.10)-

    01 mybatis框架整体概况(2018.7.10)- F:\廖雪峰 JavaEE 企业级分布式高级架构师课程\廖雪峰JavaEE一期\第一课(2018.7.10) maven用的是3.39的版本 ...

  5. 北京化工大学2018年10月程序设计竞赛部分题解(A,C,E,H)

    目录 北京化工大学2018年10月程序设计竞赛部分题解(A,C,E,H) 竞赛事件相关 竞赛链接 竞赛题目 总结 北京化工大学2018年10月程序设计竞赛部分题解(A,C,E,H) 竞赛事件相关 竞赛 ...

  6. 富士康的盈利秒杀99%的A股公司:3星|《三联生活周刊》2018年10期

    三联生活周刊·最美的数学:天才为何成群到来(2018年10期) 本期专题是数学和成都,我都跳过去没看.其他内容也还有点意思. 总体评价3星. 以下是本期一些内容的摘抄,#号后面是kindle电子版中的 ...

  7. Burn Down Chart(2018.6.4~2018.6.10)

    Burn Down Chart (2018.6.4~2018.6.10) 娄雨禛[前端部分] 曾子轩[后端部分+燃尽图] 前端 1. 娄雨禛+李鑫 1)在总工程中完成跳转,实现图片显示,并发布到Git ...

  8. Java分布式互联网架构/微服务/高性能/springboot/springcloud 2018年10月17日直播内容

    2018年10月17日直播内容 大规模并发必备的消息中间件技术ActiveMq 网盘链接: https://pan.baidu.com/s/1GlxsZ2JnrvX- YN16-S7lQw 提取码: ...

  9. C# ValueTuple 原理

    本文告诉大家一些 ValueTuple 的原理,避免在使用出现和期望不相同的值.ValueTuple 是 C# 7 的语法糖,如果使用的 .net Framework 是 4.7 以前,那么需要使用 ...

  10. Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

    概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...

随机推荐

  1. Vux的安装使用

    1.Vux的安装 1.1.vue-cli的vux模板生成项目 可以直接使用 vue-cli 的模板生成一个 vux 项目 vue init airyland/vux2 projectName 由此可以 ...

  2. 判断内网机器的真实外网IP或域名的方法总结

    在内渗透中有时需要在某台WEB服务器中留下后门,可以通过内网IP建立IPC连接,但还需要获知外网IP才能访问Wbshell,在无网关权限的情况下,我总结了有如下方法: nslookup myip.op ...

  3. java中的 sleep() 和 wait() 有什么区别?

    1.每个对象都有一个锁来控制同步访问,Synchronized关键字可以和对象的锁交互,来实现同步方法或同步块.sleep()方法正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sl ...

  4. h5视频标签 video

    video标签,用来播放视频的 基本上所有的浏览器都支持 video支持的视频格式有: mp4 mime-type: video/mp4 WebM mime-type: video/WebM Ogg ...

  5. Unity各版本差异

    Unity各版本差异 version unity 5.x 4.x  2017 差异 特点  首先放出unity的下载地址,然后再慢慢分析各个版本.再者unity可以多个版本共存,只要不放在同一目录下. ...

  6. 用Vue来实现音乐播放器(十八):右侧快速入口点击高亮

    问题一:当我们点击右侧快速入口的时候  被点击的地方高亮 首先我们要知道右侧快速入口是为什么高亮??因为当watch()监控到scrollY的变化了的时候  将scrollY的值和listHeight ...

  7. 用Vue来实现音乐播放器(十五):处理得到的歌手数据

    之前得到的歌手数据是用forEach遍历添加的  没有顺序性  我们希望得到的数据是title:"热门"的数据在最上面  title为字母的数据按字母从低到高顺序排列 var ho ...

  8. python-笔记(二)数据类型

    一.数据类型是什么鬼? 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同 ...

  9. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_04 数据结构_5_数据结构_红黑树

    生活中的树和计算机中的树.计算机的树是倒着的

  10. CDN分发

    CDN 是Content Delivery Network,即内容分发网络. 未完待续..