去年在CSDN上写的,现在把它搬过来。

一、引发问题

用了那么久的 ref out ,你真的了解它们是如何使得实参与形参的值保持同步的吗?

二、研究前提

要研究这个问题,前提是要了解 C# 中方法间参数是如何传递的:

1.CLR支持两种类型:值类型引用类型

a. 值类型:值一般保存在线程栈上,作为类对象的字段时保存在堆上。

b. 引用类型:对象实例保存在堆上,引用保存在线程栈上,值类型可以通过装箱变为引用类型。

  

 //表示引用类型
class Ref
{
private int _x;
public int X
{
get => _x;
set
{
_x = value;
}
}
} static void TestValAndRef()
{
//第一部分
int a1 = ;
var ref1 = new Ref()
{
X =
}; //第二部分
int a2 = a1;
a2 = ;
var ref2 = ref1;
ref2.X = ;
}

上述代码执行时变量的存储情况:

2.参数传递方式分为传值传引用两种。

3.对于CLR来说,使用out和ref都会生成相同的IL代码,并且元数据除了一个bit(用于记录声明方法时指定的是out还是ref)外,完全一致。

 

 //测试ref
static void TestRef(ref Ref r)
{
r = new Ref()
{
X = -
};
} //测试out
static void TestOut(out Ref r)
{
r = new Ref()
{
X = -
};
} static void Main(string[] args)
{
var ref1 = new Ref()
{
X =
}; TestRef(ref ref1);
TestOut(out Ref ref2);
}

以上代码编译出来的IL为:

可以看到,TestRef和TestOut方法对应的IL完全相同!

4.在CLR中,方法的参数以及返回值都是通过栈来保存的,这些形参虽然表示的东西和实参看起来时一致的,但是实际上是分开存储的,即形参和实参是两个不同的变量。

三、研究问题

1.CLR默认所有方法参数传递方式都是传值:

a.对于值类型来说,传递的是值的副本。例如线程栈中 a1 的值:5。

b.对于引用类型来说,传递的是对象的引用,而引用本身是传值的,调用方法内用形参把引用存起来,如果在调用方法内部更改了形参内保存的引用(new一个新对象或用对其赋另一个对象),那么该形参就与实参断了联系,随后的修改对实参不起作用;但如果引用未被改变的情况下进行了更改,实际上就是对实参进行的更改。例如线程栈中 ref1 的值:类型对象的引用。

2.当使用了ref或out后,C#传值方式就变为了传引用,类似于 C 中的 &a1,我想这里的&就是对应的ref和out吧:

a.对于值类型来说,传递的是对值的引用(可以理解为值的地址,类似于引用类型的传值方式)=> &形参,去掉&,剩下的形参实际上就是实参,所以这个形参中保存的引用永远不会被改变,也就是始终更改的是实参的值。例如对线程栈中 a1 的引用。

b.对于引用类型来说,传递的是对变量的引用(可以理解为指向实例对象引用的栈地址的引用,通俗的讲就是对象的引用是保存在栈的某个地址上,这里传递的就是对于该地址的引用)=>  &形参,这样就保证了调用方法内部使用的就是实参对象,而不是其引用的副本,所以任何更改都是对实参进行更改的。例如对线程栈中 ref1 的引用。

疏漏之处在所难免,如果有理解不对的地方请在下方留言,谢谢!

C#中ref和out的原理的更多相关文章

  1. C#中ref和out的使用与区别

    C#中ref关键字和out关键字所实现的功能差不多,都是指定一个形参按照引用传递而不是实参的副本传递.但是二者适用场景还是有些区别的:out适合用在需要retrun多个返回值的地方,而ref则适合用在 ...

  2. 学习重点:1、金典的设计模式在实际中应用2、JVM原理3、jui源代码

    学习重点:1.金典的设计模式在实际中应用 2.JVM原理 3.jui源代码

  3. C#中ref和out的区别浅析

    这篇文章主要介绍了C#中ref和out的区别浅析,当一个方法需要返回多个值的时候,就需要用到ref和out,那么这两个方法区别在哪儿呢,需要的朋友可以参考下   在C#中通过使用方法来获取返回值时,通 ...

  4. Vue.js-11:第十一章 - Vue 中 ref 的使用

    一.前言 在之前的前端开发中,为了实现我们的需求,通常采用的方案是通过 JS/Jquery 直接操纵页面的 DOM 元素,得益于 Jquery 对于 DOM 元素优异的操作能力,我们可以很轻易的对获取 ...

  5. Spring中EmptyResultDataAccessException异常产生的原理及处理方法

    Spring中EmptyResultDataAccessException异常产生的原理及处理方法 Spring中使用JdbcTemplate的queryForObject方法,当查不到数据时会抛出如 ...

  6. Fastjson-fastjson中$ref对象重复引用问题:二

    import java.util.ArrayList; import java.util.List; import com.alibaba.fastjson.JSON; import com.alib ...

  7. Fastjson-fastjson中$ref对象重复引用问题

    当你有城市数据,你需要按国内.国际.热门城市分成数组的形式给出并输出为json格式. 第一个问题,你的数据格式,需要按字母类别划分,比如: "int": { "C&quo ...

  8. React中ref的使用方法

    React中ref的使用方法 在react典型的数据流中,props传递是父子组件交互的唯一方式:通过传递一个新的props值来使子组件重新re-render,从而达到父子组件通信.当然,就像reac ...

  9. 基于接口回调详解JUC中Callable和FutureTask实现原理

    Callable接口和FutureTask实现类,是JUC(Java Util Concurrent)包中很重要的两个技术实现,它们使获取多线程运行结果成为可能.它们底层的实现,就是基于接口回调技术. ...

随机推荐

  1. javascript应该嵌入到html中的什么位置

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

  2. 前台调用微信接口成功还报Network Error

    前台   vue+springboot项目 this.api({ url:"https://.....",//微信路径 method:"post", param ...

  3. 使用Nginx的X-Accel-Redirect实现大文件下载

    在实现文件下载功能时通常有以下几种方式: 1.直接给出下载地址,例如http://****.com/test/test.rar,这种是最直接的方式,任何人都可以下载,无法控制用户的权限. 2.验证权限 ...

  4. java jar启动

    linux中启动 java -jar 后台运行程序 直接用java -jar xxx.jar,当退出或关闭shell时,程序就会停止掉.以下方法可让jar运行后一直在后台运行. 1. java -ja ...

  5. Java自学-类和对象 引用

    什么是Java中的引用? 引用的概念,如果一个变量的类型是 类类型,而非基本类型,那么该变量又叫做引用. 步骤 1 : 引用和指向 new Hero(); 代表创建了一个Hero对象 但是也仅仅是创建 ...

  6. Java自学-控制流程 switch

    Java的 switch 语句 switch 语句相当于 if else 的另一种表达方式 示例 1 : switch switch可以使用byte,short,int,char,String,enu ...

  7. 视频网站大杂烩--HTML+CSS练手项目1【Frameset】

    [本文为原创,转载请注明出处] 技术[CSS+HTML]   布局[Frameset] -------------------------------------------------------- ...

  8. java开发手册-总结与补充

    1.分层领域模型规约 1.DO( Data Object):与数据库表结构一一对应,通过 DAO 层向上传输数据源对象. 2.DTO( Data Transfer Object):数据传输对象, Se ...

  9. CentOS 6 使用 tptables 打开关闭防火墙与端口

    开启访问端口 Linux版本:CentOS release 6.9 此处以nginx访问端口8081为例 编辑:vi /etc/sysconfig/iptables 添加:-A RH-Firewall ...

  10. linux档案和目录管理(后续)

    资料来自鸟哥的linux私房菜 四:档案和目录的预设权限和隐藏权限 umask:预设权限,相比与chomd的4,2,1权限,档案满分为666,目录满分为777,umask可以预设消除部分权限,比如一个 ...