ref(也包括out)关键字肯定都会用,传值调用和传址调用也是初学写代码时都已经历过的话题,与这相关的还有一些话题,比如值类型和引用类型有什么区别等,但是如果不仔细,可能有一些概念的混淆或者理解不够清晰。本文试图以最简单的方式说明一下
  比如:对于值类型传参就是传值调用,对于引用类型就是传址调用。如果加上ref关键字那就是传址调用,引用调用时,会改变元参数值,看上去好像是的,看一个例子:
public class MyClass{  public int Id { get; set; } }

static void Invoke1(MyClass myClass)
{
myClass.Id = ;
} static void Invoke2(MyClass myClass)
{
myClass = new MyClass { Id = };
} var myClass = new MyClass { Id = };//原始值100
Invoke1(myClass);
Console.WriteLine(myClass.Id); //100变为0
Invoke2(myClass);
Console.WriteLine(myClass.Id); //依然是0

下面换一下将引用类型的参数加上ref关键字

public class MyClass{  public int Id { get; set; } }

static void Invoke1(MyClass myClass)
{
myClass.Id = ;
}
static void Invoke2(ref MyClass myClass)
{
myClass = new MyClass { Id = };
} var myClass = new MyClass { Id = };//原始值100
Invoke1(myClass);
Console.WriteLine(myClass.Id); //100变为0
Invoke2(ref myClass);
Console.WriteLine(myClass.Id); //0变为50
 
这里的现象是:
  • 引用类型的参数,函数中的改变不一定会影响原来的参数
  • 即使是引用类型,加上ref关键字以后也可能产生不一样的结果
那么ref关键字 和 传址调用还不是一回事,那怎么理解?
 
正常情况下(没有ref等关键字)的传参是怎么传的(包括引用类型和值类型)?
答案:传栈的副本
 
不管是值类型还是引用类型:

传过去的都是栈的副本:新的栈地址(栈的地址有改变) + 值副本(完全不变)

那么引用类型和值类型的参数传参行为是有区别的,区别在这里:

  • 对于值类型:值副本就是原来的值
  • 对于引用类型:值副本就是原来的堆栈地址

PS: 值类型栈上保存的值,引用类型栈上保存的托管堆的地址,真正的值在托管堆上

值类型传参对原参数无影响:栈地址和栈上的值都是副本,当然没影响

引用类型为什么有影响(不是所有情况都有影响):传过去的堆栈地址和原来的堆栈地址是同一个地址,引用类型数据在堆栈,所以操作是针对的同一个堆栈操作,堆栈值变了,原参数引用的也是这个堆栈,当然值也跟着变化。但是如果这种操作不是操作堆栈则不会影响以前的数据(比如把栈地址副本指向一个新的堆栈地址),

myClass = new MyClass { Id = 50 };

,这种操作是在堆栈上重新分配地址,然后把堆栈地址赋值给新栈副本,也就是副本栈的值不是原来的堆栈地址了,而是新的堆栈地址,那么这种改变对于原来的栈地址是没有任何影响的。

正常传参过程中值类型和引用类型内存示意图:

那么ref关键字到底是有什么作用?

答案:传参数栈
PS: 不是传栈副本,而是参数栈,那么一切都好理解了,out也是一样的,只不过必须要赋值或者指向堆栈。但是这种情况又不一样 :Method(out var parameters),有兴趣可以看一下资料
为什么string类型是传值调用?
答案:string类型传参没任何特殊性,特殊性在于string类型的操作都是开辟新的堆栈,而不是改变原来堆栈值(string类型是比较特殊的引用类型,重写了一些方法和行为,这是另外一个话题)

ref以及传值传址的理解的更多相关文章

  1. [SAP ABAP开发技术总结]Form(subroutine)、Function参数传值传址

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  2. intent传值传对象跳转

    intent传值传对象跳转 1.传值 //原activity中存入一个字段 intent = new Intent(From.this, To.class); intent.putExtra(&quo ...

  3. 关于c#中”ref”和”out”关键字的一些理解

    一. 综述(本文内容大部分来自网络,经本人整理而成,仅供学习参考,不免理解错误,欢迎批评指正) 在c#中,方法的参数传递有四种类型: (1) 传值参数(by value) 传值参数无需额外的修饰符.传 ...

  4. 使用泛型元组替代out与ref形式传参

    我们在开发的时候,都会常常遇到一个问题,如何为逻辑上返回多个对象设计方法签名.通常我们会想到使用out或ref修饰参数,或者麻烦些自己设定一个类型内部包含多个Object类型属性来接收多个返回值.这两 ...

  5. C#传真传址 结构体

    1.传真  传址 namespace 传值_传址 { class Program { //格式1:无参无返 public void LeiJia() { Console.Write("请输入 ...

  6. 浅谈对java中传参问题的理解

    之前用的c/c++比较多,在c/c++中对于传参类型,无外乎就是传值.传引用.传指针这几种.但在java中,由于没有指针类型,其传参的方式也发生了相应的变化.在网上找了找,按我之前的理解,java中传 ...

  7. react组件传值传方法

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

  8. 简谈Java传值传引用

    本随笔旨在强化理解传值与传引用   如下代码的运行结果 其中i没有改变,s也没有改变. 但model中的值均改变了. i :100s :hellomodel :testchangemodel2 :ch ...

  9. HTTP协议GET方法传参最大长度理解误区

    结论 HTTP 协议未规定GET和POST的长度 GET的最大长度是因为浏览器和WEB服务器显示了URI的长度 不同浏览器和WEB服务器,限制的最大长度不同 若要支持IE,则最大长度为2083 byt ...

随机推荐

  1. I/O模式及select、 poll、 epoll

    I/O多路复用技术 复用技术(multiplexing)并不是新技术而是一种设计思想,在通信和硬件设计中存在频分复用.时分复用.波分复用.码分复用等.在日常生活中复用的场景也非常多.从本质上来说,复用 ...

  2. C++ 半同步半异步的任务队列

    代码已发布至 HAsyncTaskQueue

  3. Python数据结构-树与树的遍历

    树:是一种抽象的数据类型 树的作用:用来模拟树状结构性质的数据集合 树的特点: 每个节点有零个或者多个节点 没有父节点的节点,叫做根节点 每一个根节点有且只有一个父节点 除了根节点外,每个节点可以分成 ...

  4. Oracle 11g数据脱敏

    Oracle 11g数据脱敏 前言 最近开发人员有个需求,导一份生产库的数据到测试库. 由于生产数据安全需要,需要并允许对导出的数据进行加密脱敏处理. 关于加密和脱敏 个人理解, 加密是通过一系列规则 ...

  5. [开源]eCharts配置简化包OptionCreator[typescript版]

    eCharts存在问题 配置eCharts的option,对于大部分的开发者来说,复杂情况下是一件繁琐的事情.为什么繁琐,大致有以下这些原因 大小写敏感:在没有IDE的智能提示下,很容易写错,而且即使 ...

  6. 编写优秀CSS代码的8个策略

    编写基本的CSS和HTML是我们作为Web开发人员学习的首要事情之一.然而,我遇到的很多应用程序显然没有人花时间真正考虑前端开发的长久性和可维护性. 我认为这主要是因为许多开发人员对组织CSS / H ...

  7. 大场前端工程师常使用CSS3特性做跨域也是牛逼前端的开始之路

    通过 CSS3 的 content 获取内容,很有意思的一个思路,实际场景中有可能用的到: CSST (CSS Text Transformation) 利用js动态创建一个link插入到文档中, 请 ...

  8. Redis哨兵集群创建脚本--v2

    1. 基础环境 操作系统版本  CentOS Linux release 7.6.1810 (Core) Docker 版本  19.03.11, build 42e35e61f3 Redis  版本 ...

  9. 实战SpringCloud通用请求字段拦截处理

    背景 以SpringCloud构建的微服务系统为例,使用前后端分离的架构,每个系统都会提供一些通用的请求参数,例如移动端的系统版本信息.IMEI信息,Web端的IP信息,浏览器版本信息等,这些参数可能 ...

  10. 论TEMP临时变量与VAR静态变量区别

    TEMP临时变量:顾名思义,这种变量类型是临时的,没有固定的存放数据的内存空间.每次扫描结束后则清零,在下个扫描周期开始时,这个变量的值都是不确定的,一般为0.使用临时变量需要遵循一个原则:先赋值再使 ...