首页 > 编程语言 >c#入参使用引用类型为啥要加ref?

c#入参使用引用类型为啥要加ref?

时间:2022-11-18 13:56:37浏览次数:38  
标签:要加 Name c# 入参 引用 Student 类型 new 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传递的是栈中存储的值,可能是一个值,也可能是一个地址引用。

标签:要加,Name,c#,入参,引用,Student,类型,new,ref
From: https://www.cnblogs.com/qwqwQAQ/p/16902885.html

相关文章

  • ​OceanBase数据库及其特点
     随着互联网行业和大数据的兴起和蓬勃发展,数据量和并发访问量呈指数级增长,这对整个系统的架构设计和产品的能力提出了巨大的挑战。极高的总拥有成本、捉襟见肘的可扩展性......
  • tomcat日志类别
    日志类别服务器⽇志catalina.out HTTP访问⽇志localhost_access_log.${date}.txtWeb应⽤⽇志localhost.${date}.log管理日志manage.log日志的级别......
  • 深度解读Webpack中的loader原理
    一、前言webpack是一个现代JavaScript应用的静态模块打包器。那么webpack是怎样实现不同种类资源模块加载的呢?没错就是通过loader。loader用于对模块的源代码进行......
  • 【Python】unicode与汉字
    一、汉字的正则表达式2E80~33FFh:中日韩符号区。收容康熙字典部首、中日韩辅助部首、注音符号、日本假名、韩文音符,中日韩的符号、标点、带圈或带括符文数字、月份,以及日本......
  • C语言:找最大交错正方形
    题目图上有一个矩阵,由N*M个格子组成,这些格子由两种颜色构成,黑色和白色。请找到面积最大的且内部是黑白交错(即两个相连的正方形颜色不能相同)的正方形。输入格式:第一行两......
  • Spring Cloud Circuit Breaker 使用示例
    SpringCloudCircuitBreaker使用示例作者:Grey原文地址:博客园:SpringCloudCircuitBreaker使用示例CSDN:SpringCloudCircuitBreaker使用示例说明SpringClo......
  • Webpack中的plugin插件机制
    大家有没有遇到过这些问题:webpack打包之后的文件没有压缩静态文件要手动拷贝到输出目录代码中写了很多环境判断的多余代码上一篇「webpack核心特性」loader说到......
  • 详解webpack构建优化
    当项目越来越复杂时,会面临着构建速度慢和构建出来的文件体积大的问题。webapck构建优化对于大项目是必须要考虑的一件事,下面我们就从速度和体积两方面来探讨构建优化的策略......
  • Ids | Openiddict 客户端获取token后依然无法访问服务端接口问题记录(汇总)
    使用IDentityService4或Openiddict时,客户端在认证通过后,有时候依然无法访问服务端。常见的异常有:1、认证服务器配置的认证URL与客户端调用的URL不匹配2、Scope未被正确添......
  • Vue3, setup语法糖、Composition API全方位解读
    起初Vue3.0暴露变量必须return出来,template中才能使用;Vue3.2中只需要在script标签上加上setup属性,组件在编译的过程中代码运行的上下文是在setup()函数中,无......