C#语法糖系列 —— 第二篇:聊聊 ref,in 修饰符底层玩法

自从 C# 7.3 放开 ref 之后,这玩法就太花哨了,也让 C# 这门语言变得越来越多范式,越来越重,这篇我们就来聊聊 ref,本质上来说 ref 的放开就是把 C/C++ 指针的那一套又拿回来了,而且还封装成一套自己的玩法,下面一一解读下。

一:方法参数上的 ref

我想设计者的初心把 ref 的功能限制的死死的,可能也考虑到 C# 是一门面向业务开发的语言,讲究的是做项目快狠准,性能反而不是第一要素,这个时候的 ref 很简单,看一下代码:

class Program{static void Main(string[] args){long price = 0;GetPrice(ref price);Console.WriteLine($"output: price={price}");}public static void GetPrice(ref long price){price = 10;}}output: price=10

我相信很有朋友都知道,方法参数中的 ref long price  拿的是栈地址,对栈地址上的值进行修改,自然就修改了指向这些地址上的变量,和引用类型原理一致,接下来我们从汇编角度去验证,在 Price 方法上下一个断点。

D:\net5\ConsoleApp4\ConsoleApp3\Program.cs @ 16:
026b048e 8d4dec          lea     ecx,[ebp-14h]
026b0491 ff15a0ebc800    call    dword ptr ds:[0C8EBA0h] (ConsoleApp3.Program.GetPrice(Int64 ByRef), mdToken: 06000002)
026b0497 90              nop
0:000> bp 026b0491
0:000> g
Breakpoint 1 hit
ChangeEngineState
eax=00000000 ebx=0057f354 ecx=0057f2d4 edx=783aaa50 esi=02979e7c edi=0057f2dc
eip=026b0491 esp=0057f2c4 ebp=0057f2e8 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
026b0491 ff15a0ebc800    call    dword ptr ds:[0C8EBA0h] ds:002b:00c8eba0=00c2be10

从汇编的 lea ecx,[ebp-14h] 就能看到,将 ebp-14 这个单元的内存地址给了 ecx,这个 ecx 也就是作为参数传递给了 Price 方法,后续的赋值将会影响这个栈位置 上的内容。

2. 方法返回值上的 ref

这就有意思了,进入的时候传地址,回来的时候也想传地址,很显然方法线程栈上的 值类型 是传不出去的,毕竟方法返回后,esp,ebp 所控制的方法栈帧空间是要销毁的,所以只能是堆上对象才能实现。

为了方便理解,看如下代码:

class Program{static void Main(string[] args){ref long price = ref GetCurrentPrice();price = 12;Console.WriteLine($"output: price={price}");}public static ref long GetCurrentPrice(){long[] nums = { 10, 20, 30 };return ref nums[1];}}output: price=12

可以看到当前的 price=12,同时 nums 这个数组也被修改了,可以用 windbg 验证一下。

0:000> !dumpheap  -type System.Int64[] Address       MT     Size
027ca7b0 04c39d00       36     Statistics:MT    Count    TotalSize Class Name
04c39d00        1           36 System.Int64[]
Total 1 objects
0:000> dq 027ca7b0 L4
027ca7b0  00000003`04c39d00 00000000`0000000a
027ca7c0  00000000`0000000c 00000000`0000001e

可以看到上面的 000000000000000c 被修改成 price=12 ,这时候有人就不爽了,我不希望外面的代码能修改 price 内容,那怎么办呢?还得在 ref 后面加上 readonly ,改造后如下:

4150fa9fa4222a8f82f47d73e30d0240.png

到此时写法就有点疯狂了,对 C# 开发者来说很难理解,对熟悉 C/C++ 指针的朋友来说又很不习惯,太纠结了,下面是一段翻译过来的 C/C++指针代码

const long long* getcurrentprice();int main()
{int i = 0;const long long* price = getcurrentprice();price = 12;printf("num=%d, price=%d \n", i, *price);}const long long* getcurrentprice() {long long* num = new long long[3]{ 10,20,30 };return num + 1;
}

说实话,这代码看起来就清爽多了。

2. 对 ref 变量的 in 操作

这又是一套 C/C++ 的玩法,有时候不希望某一个方法对 ref 变量进行修改,注意:是不希望某一个方法进行修改,其他方法是可以的,那这个怎么实现呢?这就需要在入参上加 in 前缀,把代码修改一下。

class Program{static void Main(string[] args){ref long price = ref GetCurrentPrice();ModifyPrice(in price);Console.WriteLine($"output: price={price}");}public static ref long GetCurrentPrice(){long[] nums = { 10, 20, 30 };return ref nums[1];}public static void ModifyPrice(in long price){price = 12;Console.WriteLine(price);}}
ae42654c07815e0ee44f5c33aabc763b.png

可以看到,这时候报错了,如果换成 C++ 就很简单了,只需要在参数上把 in 改成 const 即可。

void modifyprice(const long long* price) {*price = 12;printf("%d", *price);
}
fd0ad8a96b0176f12a82999212804cb1.png

总的来说,ref 这一套玩法太另类了 🤣🤣🤣

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/288264.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python发邮件脚本详解_Python发送邮件脚本

在一些场景中经常需要发送邮件, 像是持续集成和运维报警等. 而使用Python脚本能够很快捷方便得实现发送各种邮件的需求.这里就通过Python基于SMTP(Simple Mail Transfer Protocol)实现一套可以群发,Html内容和附件的脚本。既然是要发送各种类型的邮件, 首先需要有一个邮箱.这里…

(二)python3 只需3小时带你轻松入门——基本变量

输入 在程序运行过程中,数据从外部流向程序,称为输入。在程序运行过程中,接收用户从键盘上键入值,可以使用input()函数。 input("请输入你要输入的值:")在输入值时,一般是代表接下来的运算需要使用到用户所…

最好的车

最好的车 Time Limit : 3000/1000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other) Total Submission(s) : 18 Accepted Submission(s) : 6 Problem Description H城是一个旅游胜地。每年都有成千上万的人前来观光。为方便游客。巴士公司在各个旅游景点及宾馆、…

Fiddler之为什么我没有抓到网络请求的js链接

1 问题 我开了Fiddler,没有抓到js的连接请求,因为我需要替换js文件,我以为我是没有开启抓起https的连接,但是的确开启了。 2 原因 浏览器里面有缓存,部分js文件不会再进行请求。 2 解决办法 在浏览器页面按下F12,然…

Asp.net MVC 中Controller返回值类型ActionResult

目录 1、返回ViewResult视图结果,将视图呈现给网页 2、 返回PartialViewResult部分视图结果,主要用于返回部分视图内容,在View/Shared目录下创建ViewUserControl.cshtml部分视图

html5一年四季的变化,家乡四季的变化作文(精选5篇)

家乡四季的变化作文(精选5篇)在日常生活或是工作学习中,大家或多或少都会接触过作文吧,写作文是培养人们的观察力、联想力、想象力、思考力和记忆力的重要手段。那么你有了解过作文吗?下面是小编精心整理的家乡四季的变化作文(精选5篇)&#…

ThinkPHP多次重复提交问题的根源

2019独角兽企业重金招聘Python工程师标准>>> 由于用户刷新网页,导致页面所有变量回归初始空值 $code_session2 session(code2); $code2 I(code2);if($code2 ! $code_session2) {session(code2, $code2);M(dati)->data($data)->add();} 解决方法是…

基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入

系列文章基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客?基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目基于.NetCore开发博客项目 StarBlog - (3) 模型设计基于.NetCore开发博客项目 StarBlog - (4) markdown博客批量导入...前言…

(一)python3 只需3小时带你轻松入门—— 编程尝试

什么是函数? 在编程中,函数和通常数学中的函数概念并不完全相同;编程中的函数更接近于一个写好的工具,在开发某些功能时,所需要到该函数,就把该函数拿过来使用。 输出/显示 运行python程序时显示指定的文本…

HTTP 笔记与总结(7)HTTP 缓存(配合 Apache 服务器)

在网络上&#xff0c;有一些缓存服务器&#xff0c;另外浏览器自身也有缓存功能。 例如&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title> </head> <body&…

linux之dos2unix命令解决vi打开文件行尾巴显示^M

1 问题 有时候我们用vi打开文件,行尾巴显示^M,我之前也不知道这个是为什么,后面才了解到,DOS格式的文本文件在Linux平台,用较低版本的vi打开文件行尾会显示^M,DOS下的文本文件是以\r\n作为断行标志的,表示成十六进制就是0D 0A。而Unix下的文本文件是以\n作为断行标志的,…

bootstrap 一排5个_Bootstrap5 列(Columns)

对其使用flexbox对齐工具来垂直和水平对齐列。垂直对齐One of three columnsOne of three columnsOne of three columnsOne of three columnsOne of three columnsOne of three columnsOne of three columnsOne of three columnsOne of three columnsOne of three columnsOne o…

ASP.NET MVC下的四种验证编程方式

ASP.NET MVC采用Model绑定为目标Action生成了相应的参数列表,但是在真正执行目标Action方法之前,还需要对绑定的参数实施验证以确保其有效性,我们将针对参数的验证成为Model绑定。总地来说,我们可以采用4种不同的编程模式来进行针对绑定参数的验证。 目录 一、手工验证绑…

台式计算机idc数据排名,IDC数据出炉 海尔电脑排名持续上升

2011年上半年&#xff0c;国内PC产品呈现缓慢增长态势。近期IDC公布了第二季度最新排名&#xff0c;数据显示&#xff0c;海尔电脑消费类台式机在华北市场持续增长&#xff0c;连续两个季度再度排名亚军。华南市场同样取得了好成绩&#xff0c;台式机由第四上升至第三&#xff…

httpcilent绕过证书

2019独角兽企业重金招聘Python工程师标准>>> 对接其他公司接口&#xff0c;测试环境没有问题&#xff0c;生产环境出现https证书认证的问题&#xff0c; 网上搜了许久才发现一个&#xff0c;链接&#xff1a;http://pan.baidu.com/s/1dEDSmY1 密码&#xff1a;dpsb …

如何让apache支持.htaccess 解决Internal Server Error The server …错误

如何让apache支持.htaccess 解决Internal Server Error The server …错误 文章来源&#xff1a;小灰博客| 时间&#xff1a;2013-12-25 12:17:08| 作者&#xff1a;Leo | 2 条评论 文章分类&#xff1a;IT技术分享、PHP、小技巧 标签&#xff1a; .htaccess、apache 今天…

C# Linq源码解析之All

前言在Dotnet开发过程中&#xff0c;All作为IEnumerable的扩展方法&#xff0c;十分常用。本文对Aggregate方法的关键源码进行简要分析&#xff0c;以方便大家日后更好的使用该方法。使用确定序列中的所有元素是否都满足条件,如果都满足就返回true&#xff0c;如果有一个不满足…

(六)python3 只需3小时带你轻松入门——循环

for循环 使用循环可以重复执行某些代码&#xff0c;可以方便程序编写&#xff1b;但是不记效率的使用循环会使程序运行效率降低。 range 使用range()函数可以生成多个连续整数的range对象(这个概念后面会说)。基本格式&#xff1a;range(end)其中end是结尾数。range(10)则会生…

linux下查看mysql的当前连接情况

为什么80%的码农都做不了架构师&#xff1f;>>> 首先需要登录到mysql中。 总共有三个命令&#xff1a; 1、status mysql> status--------------mysql Ver 14.14 Distrib 5.5.30, for Linux (x86_64) using readline 5.1Connection id: 96Current data…

菜鸟学ASP.NET MVC4入门笔记

ASP.NET MVC 是微软官方提供的以MVC模式为基础的ASP.NET Web应用程序(Web Application)框架,它由Castle的MonoRail而来。 MVC 编程模式 MVC 是三种 ASP.NET 编程模式中的一种。 MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式。 (…