再谈CLR:值类型按照引用传递(以及与装箱拆箱的区别)
来源:互联网 发布:linux oracle11g卸载 编辑:程序博客网 时间:2024/05/17 04:05
经常被问到这样的问题:值类型能不能按引用传递?传递之后又是什么样的处理方式
当然是可以的,不管是现在还是以前都可以。我们来看看下面两个方法的区别
static void TestMethod(int a) { a = 5; Console.WriteLine(a); } static void TestMedhot2(ref int a) { a = 5; Console.WriteLine(a); }.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
我们知道int是值类型,在第一个方法中,我们按照默认的方式进行传递,其实就是所谓的按值传递。
我们看到在IL_0002这个地方,是把a这个变量压入了栈。也就是说,此时在栈中是有一个a变量代表的值的 ,例如5
然后我们再来看另外一个方法。首先从直观上看,int32&和int32肯定是有区别的,我们都知道在C++中,&表示指针的意思
然后,我们并没有看到它将a这个变量压入栈中。那么他到底是做了什么事情呢
注意,虽然按照引用传递,但这个与“装箱和拆箱”还不是一回事情。什么时候发生装箱拆箱呢?就是将值类型转换为了引用类型(一般指Object).假设我们如下的方法
static void TestMethod3(object a) { Console.WriteLine(a); }.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
然后,我们在Main里面去调用
int a = 7; TestMethod(a); TestMedhot2(ref a); TestMethod3(a);.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
这里调用TestMethod3的时候会发生装箱
也就是说,如果仅仅是按引用传递参数的话,那么不会发生装箱和拆箱的问题。也就是说,它并没有产生另外一份数据,而是用指针的方式指向了参数所代表的那份数据而已(这份数据可能在栈上面,也可能在堆上面),但总之是一个指针引用,所以说,按照引用传递的情况,我们如果在TestMetho2中修改了a的值,那么后续访问a这个变量,它的值就确实被改变了。
思考一下:为什么说可能在堆上面呢?
下面有一个完整的例子
using System;namespace ConsoleApplication1{ class Program { static void Main(string[] args) { int a = 7; Console.WriteLine("原始值:{0}",a); TestMethod(a); Console.WriteLine("按值传递调用后:{0}", a); TestMedhot2(ref a); Console.WriteLine("按引用传递调用后:{0}", a); TestMethod3(a);//这里发生装箱 Console.WriteLine("装箱操作传递调用后:{0}", a); Console.WriteLine(a); Console.Read(); } static void TestMethod(int a) { a = 5; Console.WriteLine(a); } static void TestMedhot2(ref int a) { a = 5; Console.WriteLine(a); } static void TestMethod3(object a) { int _a = (int)a;//这里发生拆箱 Console.WriteLine(_a); } }}.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
- 再谈CLR:值类型按照引用传递(以及与装箱拆箱的区别)
- csharp004值类型引用类型区别,以及装箱拆箱以及转换相关
- 变量,常量,引用类型,值类型,枚举类型, 值类型和引用类型的简单区别,类型转换,装箱与拆箱
- 值类型与引用类型区别and装箱与拆箱
- C# 引用类型、值类型与拆箱、装箱
- 值类型、引用类型、拆箱装箱
- 引用类型和值类型(装箱和拆箱)
- c# 值类型和引用类型的区别,装箱,拆箱。
- java学习(1) 引用类型值类型区别 引用传递值传递的区别
- 值类型和引用类型的转换(装箱和拆箱)
- C# 数据类型的引用类型、值类型内存存储方式以及区别; 函数参数传递的引用传递(址传递)、值传递区别
- CLR via c# 装箱与拆箱
- 值类型传递和引用类型传递的区别
- 堆和栈、值类型与引用类型、装箱与拆箱
- C#值类型与引用类型,装箱与拆箱操作
- 值传递与引用传递的区别
- 值传递与引用传递的区别?
- java 值传递与地址传递(引用)的区别
- 修改应用程序搜索程序集的私有路径
- 如何实现多文件下载(实例)
- 环境变量(Environment Variable)那点事
- 再谈CLR:GAC目录的构造
- 再谈CLR:如何通过代码获取程序集所引用的程序集信息
- 再谈CLR:值类型按照引用传递(以及与装箱拆箱的区别)
- 再谈CLR:无法避免的装箱
- 再谈CLR:MSCorEE.dll文件的奥秘
- 再谈CLR:CLR的版本
- 再谈CLR:目标平台的问题
- 再谈CLR:查看程序集的依赖关系
- 再谈CLR: .NET 4.0新功能:Mscoree.dll + Mscoreei.dll=更少的Reboot (上)
- 用户身份验证之Windows验证
- 用户验证之自定义身份验证