c#入参使用引用类型为啥要加ref?
摘一段来自官网的说明 :方法的参数列表中使用 ref 关键字时,它指示参数按引用传递,而非按值传递。 ref 关键字让形参成为实参的别名,这必须是变量。 换而言之,对形参执行的任何操作都是对实参执行的。
大体意思就是将实惨的引用作为参数传递,如果入参不加ref修饰,本身传递的是实参的值到方法中。
那什么是值,什么是引用?大体可以理解为堆栈的区别,在.net中大多数实例存在于托管堆栈中。struct,int32,int64,double,enum等数据类型声明的实例存在栈中,而string,class,delegate等存在于堆中。前者一般称为值类型,后者则叫做引用类型,那么引用类型和值类型在内存中的大概图如下:

可以看到引用类型被存储的时候真正内容存在堆中,而在stack中存储了一个堆中地址的引用指向堆中真正内容。
ref修饰入参的常用场景
当我们希望一个已有返回值的方法能够修改我一个外部基本类型的值的时候,我们可以将该参数加上ref关键字作为入参。具体原理其实就是将栈中具体的值替换为了栈的引用,说白了就是地址,幻想一下本来你高考作弊只是后台改了一下自己成绩和学霸一样,学霸的人生没有受到影响,现在你干脆把学霸的试卷改成了自己名字,学霸直接被你影响只能进厂打螺丝了,当然这个比喻不是很贴切,大家理解到意思就行。
那么为什么引用类型的入参我们不需要要添加ref?因为从上图我们能看出来栈中存储的本来就是引用类型的地址,所以引用类型不需要添加ref关键字,当你在方法内部修改了入参的一些属性值,外面的实惨依旧会受到影响。
引用类型添加ref的作用是啥?
我们在实际开发中还是能够碰到一些引用类型添加ref的场景。其实道理也是一样的,就是将引用类型的栈的地址传递到了方法中,那么和不添加有啥区别?我们来看看下面的代码:
Student student1 = new Student("Jack");
Student student2 = new Student("Lucy");
WithoutRef(student1);
WithRef(ref student2);
Console.WriteLine($"不带ref的方法---{student1.Name}");
Console.WriteLine($"带ref的方法---{student2.Name}");
Console.Read();
//不带ref的方法
static void WithoutRef(Student stu)
{
stu.Name = "Bruce";
}
//不带ref的方法
static void WithRef(ref Student stu)
{
stu.Name = "Bruce";
}
public class Student
{
public Student(string name)
{
Name = name;
}
public string Name { get; set; }
}

可以看到结果一样的,两个实例的名字都变了
那我们再看看下面的代码:
Student student1 = new Student("Jack");
Student student2 = new Student("Lucy");
WithoutRef(student1);
WithRef(ref student2);
Console.WriteLine($"不带ref的方法---{student1.Name}");
Console.WriteLine($"带ref的方法---{student2.Name}");
Console.Read();
//不带ref的方法
static void WithoutRef(Student stu)
{
stu = new Student("Bruce");
}
//不带ref的方法
static void WithRef(ref Student stu)
{
stu = new Student("Bruce");
}
public class Student
{
public Student(string name)
{
Name = name;
}
public string Name { get; set; }
}

我们发现第一个不带ref的方法名字没有发生变化。
代码的变化就是第二个例子重新new了一下,我们根据上面的原理分析就能知道为啥。由于ref将引用类型的栈地址传递过去了,new关键字大体就是在堆中开辟一个新空间,然后将空间地址存储到栈中,由于ref将栈地址传递过来了,所以就将栈中的存储地址替换为了新开辟的堆地址了,而不带ref的引用类型本身传递的只是堆中地址的引用,所以new关键字等于说将形参重新开辟空间和分配了,和实参已经不是同一个地方了。
总结
ref传递的是栈地址
不带ref传递的是栈中存储的值,可能是一个值,也可能是一个地址引用。
c#入参使用引用类型为啥要加ref?的更多相关文章
- 引用类型前需要加ref?
方法的参数前加ref代表的是传的参数的地址,值类型前加ref的作用相当于把这个值类型当成引用类型在用,那引用类型作为参数有一种情况也需要加ref,不然得到的值会有差. 不加ref: class Pro ...
- js的replace函数入参为function时的疑问
近期在写js导出excel文件时运用到replace方法,此处详细的记录下它各个参数所代表的的意义. 定义和用法 replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式 ...
- oracle常用函数以及调用入参为record的存储过程的方法,
转自:http://www.cnblogs.com/zhangronghua/archive/2007/08/20/862812.html SQL中的单记录函数1.ASCII返回与指定的字符对应的十进 ...
- Egg.js 中入参的校验
日常作业中免不了频繁处理 GET/POST 的入参,你当然可以每个 action 中都重复地去做这些事情, 从 query 或 body 取出入参, 对可选的入参进行判空, 处理入参的类型转换, 对入 ...
- Saiku根据入参日期查询出对应的数据(二十)
Saiku根据入参日期查询出对应的数据 之前好像有写过一篇博客关于saiku date range的,现在进一步更新啦!!! 这里的日期筛选会更完善一些,需要提供两个参数 开始日期与结束日期(star ...
- 来啊踩fastjson打印入参导致业务跑偏的坑
线上代码对日志的记录,重要性自不必说.但是怎样记录日志也是有讲究的! 日志可以直接在每个方法中进行日志记录,优点是想怎么记就怎么记,缺点是记日志的代码可能会超过你的业务代码,可读性急剧下降,这也是日志 ...
- Oracle存储过程入参传入List集合的小例子
第一步:创建一个对象类型 create or replace type STUDENT as object( id ), name ), age ) ); / 第二步:创建一个数组类型 (任意选择下面 ...
- spring boot 三种入参
先来讲述下最简单的使用get请求用户信息的实现方式,代码如下,写好后直接在Application类点击右键有个RunAs,点击后会自动运行,运行成功后可以使用http发包工具进行测试,这里推荐使用ch ...
- springboot-mvc:入参日期类型转换String->Date
4种方式: 1.通过在application.ym中配置 spring.mvc.data-format: yyyy-MM-dd HH:mm:ss ,使用的是ParserConverter 优点:简单的 ...
- @Validated和@Valid区别:Spring validation验证框架对入参实体进行嵌套验证必须在相应属性(字段)加上@Valid而不是@Validated
Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR- ...
随机推荐
- Windows平台真实时毫秒级4K H264/H265直播技术方案
背景 在刚提出4K视频的时候,大多数人都觉得没有必要,4K的出现,意味着更高的硬件规格和传输要求,1080P看的很爽.很清晰,完全满足了日常的需求.随着电视的尺寸越来越大,原本1080P成像已经无法满 ...
- RTSP播放器或RTMP播放器常用的Evnet事件回调设计
很多开发者在开发RTSP或RTMP播放器的时候,不晓得哪些event回调事件是有意义的,针对此,我们以大牛直播SDK(github)的Android平台RTSP/RTMP直播播放端为例,简单介绍下常用 ...
- 大家都能看得懂的源码之 ahooks useVirtualList 封装虚拟滚动列表
本文是深入浅出 ahooks 源码系列文章的第十八篇,该系列已整理成文档-地址.觉得还不错,给个 star 支持一下哈,Thanks. 简介 提供虚拟化列表能力的 Hook,用于解决展示海量数据渲染时 ...
- Java 多线程:并发编程的三大特性
Java 多线程:并发编程的三大特性 作者:Grey 原文地址: 博客园:Java 多线程:并发编程的三大特性 CSDN:Java 多线程:并发编程的三大特性 可见性 所谓线程数据的可见性,指的就是内 ...
- ElasticSearch介绍和基本用法(一)
ElasticSearch 引言 1.在海量数据中执行搜索功能时,如果使用MySQL, 效率太低. 2.如果关键字输入的不准确,一样可以搜索到想要的数据. 3.将搜索关键字,以红色的字体展示. 介绍: ...
- .NET 实现启动时重定向程序运行路径及 Windows 服务运行模式部署
日常工作中有时候会遇到需要将程序直接在服务器上运行,而不依赖于 IIS 托管的情况,直接运行有两种方式,一种是部署为 服务模式,另一种则是 直接启动 .NET 发布之后的 exe 文件以 控制台模式运 ...
- WinUI 3 踩坑记:第一个窗口
本文是 WinUI 3 踩坑记 的一部分,该系列发布于 GitHub@Scighost/WinUI3Keng,文中的代码也在此仓库中,若内容出现冲突以 GitHub 上的为准. WinUI 3 应用的 ...
- Elasticsearch中的一些重要概念:cluster, node, index, document, shards及replica
首先,我们来看下一下如下的这个图: Cluster Cluster也就是集群的意思.Elasticsearch集群由一个或多个节点组成,可通过其集群名称进行标识.通常这个Cluster 的名字是可以在 ...
- opencv cv.line
''' 本次来学习基于opencv进行各种画图操作,以前只习惯用matplotlib,最近开始用opencv,觉得也很好用. cv.line(), cv.circle() , cv.rectangle ...
- PAT (Basic Level) Practice 1010 一元多项式求导 分数 25
设计函数求一元多项式的导数.(注:xn(n为整数)的一阶导数为nxn−1.) 输入格式: 以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过 1000 的整数).数字间以空格分隔. 输出格式: ...