C#值传递和引用传递,ref和out关键字,装箱和拆箱

C#值传递和引用传递

1.值传递和引用传递

值传递:值传递时,系统首先为被调用方法的形参分配内存空间,并将实参的值按位置一一对应复制给形参,被调用方法中形参得任何改变都不会影响到相应的实参。

引用传递时:系统不是将实参本身得值赋值后传给形参,而是将其引用值(地址值)传递给形参。因此形参所引用得该地址上的变量与传递的实参相同,方法体内相应的形参值得任何改变都会影响到作为引用传递的实参。

C# 复制代码
Console.WriteLine("#####################下面是值传递和引用传递的测试代码#####################");
            Console.WriteLine();

            //值传递
            int Age1 = 18;
            Console.WriteLine($"值参数传递前Age1的值:{Age1}");
            //调用方法
            AgeAdd(Age1);
            Console.WriteLine($"值参数传递后Age1的值:{Age1}");

            Console.WriteLine();

            //引用传递
            Student stu = new Student();
            stu.Age = 28;
            Console.WriteLine($"引用参数传递前Age1的值:{stu.Age}");
            //调用方法
            AgeAdd(stu);
            Console.WriteLine($"引用参数传递前Age1的值:{stu.Age}");

            Console.ReadKey();

//使用的方法
 public static void AgeAdd(int age)
        {
            age += 10;

            Console.WriteLine("值传递方法中参数的值: Age : " + age);
        }

        public static void AgeAdd(Student stu)
        {
            stu.Age += 10;

            Console.WriteLine("引用传递方法中参数的值: Age : " + stu.Age);
        }

运行结果:

2.ref与out实现值类型的引用传递

(1)ref指定的参数在函数调用时必须先初始化(必须在执行方法之前给ref修饰的参数赋值),out不用。

(2)out指定的参数在进入函数时会清空自己,因此必须在函数内部进行初始化操作(必须在方法体内给out修饰的变量赋值)后才能使用;而ref不用。

(3)ref可以将值传到方法内,也可以将值传到方法外

(4)out只能将值传到方法外

(5)string是特殊的引用类型,操作与值类型看齐(需要单独的加上ref和out)

注:1.可以通过ref和out来决定值类型变量是否按照引用传递

2.声明方法时形参需要带ref和out关键字,调用方法时传入的实参也需要带ref和out关键字

C# 复制代码
            Console.WriteLine("#####下面是ref和out的测试代码#####");

            //ref------num1必须在方法调用前初始化
            int num = 5;

            Console.WriteLine($"执行带ref参数的方法前num的值:{num}");

            RefDoubleValue(ref num);

            Console.WriteLine($"执行带ref参数的方法后num的值:{num}");

            Console.WriteLine($"--------------分割线-----------------");

            //out------num2无须在方法调用前初始化
            int num2 = 10;

            //为了对比所有初始化num2的值
            Console.WriteLine($"执行带out参数的方法前num的值:{num2}");

            //调用方法
            OutDoubleValue(out num2);

            Console.WriteLine($"执行带out参数的方法后num的值:{num2}");

            Console.ReadKey();

		//相关方法 
		//带ref参数的方法
		public static void RefDoubleValue(ref int num)
        {
            num = num * 2;
        }
		
		//带out参数的方法
        public static void OutDoubleValue(out int num)
        {
            //方法内部使用前必须初始化
            num = 9;

            num = num * 2;
        }

运行结果:

3.装箱和拆箱

(1)装箱:把值类型装换成引用类型

(2)拆箱:把引用类型装换成值类型

(3)装箱时是不需要显式的类型转换的,不过拆箱需要显示的类型转换。

装箱具体发生了什么:对象类型在堆中分配一个对象实例,并将值类型的实例复制到新对象中。

第一步:新分配托管堆内存(大小为值类型实例大小加上一个方法表指针)

第二步:将值类型的实例(也就是值,数据)拷贝到新分配的内存中

第三步:返回托管堆中新分配对象的地址(这个地址就是一个指向对象的引用)。

拆箱具体发生了什么:检查对象实例,确保它是给定值类型的一个装箱值;然后再将该值从对象实例复制到值类型变量中。

复制代码
            Console.WriteLine("#####下面是装箱和拆箱的测试代码#####");

            //定义一个整型变量
            int num = 5;

            //将整型转换为对象类型(隐式)------装箱
            Object obj = num;

            Console.WriteLine($"将整型变量num装箱后obj变量的值:{obj}");

            Console.WriteLine($"--------------分割线-----------------");

            //将对象类型转换为整型(显式)------拆箱
            int num2 = (int)obj;

            Console.WriteLine($"将引用变量obj拆箱后num变量的值:{num2}");

            Console.ReadKey();

运行结果:

频繁的装箱拆箱比较浪费系统资源。

相关推荐
傻傻虎虎19 分钟前
【QT】ModbusTCP读写寄存器类封装
开发语言·数据库·qt
独行soc26 分钟前
2025年渗透测试面试题总结-华顺信安[实习]安全服务工程师(题目+回答)
运维·开发语言·学习·安全·面试·渗透测试·php
王RuaRua37 分钟前
[数据结构]6. 队列-Queue
开发语言·数据结构·算法·leetcode
姜行运42 分钟前
数据结构【AVL树】
android·数据结构·c#
敲键盘的小夜猫1 小时前
如何理解大模型的幻觉输出及RAG技术的应用与实战案例
开发语言·python
恒者走天下1 小时前
c++学习方向选择说明
开发语言·c++·学习
zhangpeng4555479401 小时前
C++编程起步项目
开发语言·前端·c++
KeithTsui2 小时前
C语言之 比特(bit)、字节(Byte)、字(Word)、整数(Int)
linux·c语言·开发语言·c++·算法·word
fashia2 小时前
Java转Go日记(四十四):Sql构建
开发语言·后端·golang·go
lsnm3 小时前
【LINUX操作系统】生产者消费者模型(下):封装、信号量与环形队列
linux·运维·服务器·开发语言·c++·ubuntu·centos