C#中参数为引用类型加ref和不加的区别
2017-05-27 02:19
477 查看
首先说说两种数据类型:值类型和引用类型的区别
声明一个值类型的变量会在栈上分块空间用来存储变量的值,如int a= 1,a的值直接存储在栈上
在调用Method(a)时,可以理解为将a赋值给了b,即ClassA b = a,这下就好理解了吧,就是在栈上分配了个新的地址,然后指向了a,这就相当于a、b地址不同,但都指向同一个对象。那么在Method中堆b的所有更改都会反应到a上。我用下面的代码做了个验证
运行结果
从运行结果中可看出,main方法和GetDearName方法中info的地址是不一样的,但是哈希code是一致的,证明了上面的说法。
再看下面的代码:
通过运行结果,看以看出,当把另一个对象赋值给info时,main中的HashCode和GetDearName中info的HashCode不一致了,GetDearName中的info指向了另外一个对象,这将不满足把GetDearName中info的变化反应到Main中的info上了。这也就是ref的作用。
在GetDearName中的参数前面显示加上ref关键字,则表示传递的参数就是main中info的地址,没有重新分配栈地址。这样就算GetDearName中执行info=user,main中的info也会指向user这个对象,但是地址没有发生变化,把上面的GetDearName方法的参数前加上ref关键字,main调用中也加上,结果如下图
Mark下,如有不对之处,欢迎指出。
值类型
包含int、double、char、bool、struct、还有枚举enum,声明一个值类型的变量会在栈上分块空间用来存储变量的值,如int a= 1,a的值直接存储在栈上
引用类型
包含类、string、object,Interface,引用类型的对象或实例存储在堆上,而栈上存储的是指向这个堆的地址如ClassA s= new ClassA;画了个简单的示意图ref的作用
好了,下面来说说引用类型的参数加ref和不加的区别,其实从上面可以知道,引用类型的参数传递传的都不是对象本身,而是地址。不加ref关键字,我们可以看成是把对象赋值给了另外一个地址,然后把这个地址作为参数传递到方法中。如下面这段代码static main() { ClassA a = new ClassA(); Method(a); } public void Method(ClassA b) { }
在调用Method(a)时,可以理解为将a赋值给了b,即ClassA b = a,这下就好理解了吧,就是在栈上分配了个新的地址,然后指向了a,这就相当于a、b地址不同,但都指向同一个对象。那么在Method中堆b的所有更改都会反应到a上。我用下面的代码做了个验证
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace MyTest02 { class Program { static void Main(string[] args) { UserInfo info = new UserInfo(); info.UserName = "wenjl"; string addr1 = GetMemory(info); Console.WriteLine("main 中 info 的地址:{0}", addr1); Console.WriteLine("调用方法之前的哈希code:{0}",info.GetHashCode()); string dearNm = GetDearName(info); int code = info.GetHashCode(); Console.WriteLine("main 中哈希code:{0}",code); Console.ReadLine(); } /// <summary> /// 获取昵称 /// </summary> /// <param name="info"></param> public static string GetDearName(UserInfo info) { string dearName = "Bad Boy"; if ("wenjl".Equals(info.UserName)) { dearName = "Good Boy"; } info.DearName = dearName; string addr2 = GetMemory(info); Console.WriteLine("GetDearName 中 info 的地址:{0}", addr2); int code = info.GetHashCode(); Console.WriteLine("GetDearName 中哈希code:{0}", code); return dearName; } public static string GetMemory(object o) { GCHandle h = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); IntPtr addr = GCHandle.ToIntPtr(h); return "0x" + addr.ToString("X"); } } }
运行结果
从运行结果中可看出,main方法和GetDearName方法中info的地址是不一样的,但是哈希code是一致的,证明了上面的说法。
再看下面的代码:
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace MyTest02 { class Program { static void Main(string[] args) { UserInfo info = new UserInfo(); info.UserName = "wenjl"; string addr1 = GetMemory(info); Console.WriteLine("main 中 info 的地址:{0}", addr1); Console.WriteLine("调用方法之前的哈希code:{0}",info.GetHashCode()); string dearNm = GetDearName(info); int code = info.GetHashCode(); Console.WriteLine("main 中哈希code:{0}",code); Console.ReadLine(); } /// <summary> /// 获取昵称 /// </summary> /// <param name="info"></param> public static string GetDearName(UserInfo info) { Console.WriteLine("GetDearName中 赋值之前的哈希code:{0}", info.GetHashCode()); UserInfo user = new UserInfo() { DearName = "Bad Boy", UserName = "wenjl" }; string dearName = "Bad Boy"; if ("wenjl".Equals(info.UserName)) { dearName = "Good Boy"; } info = user; string addr2 = GetMemory(info); Console.WriteLine("GetDearName 中 info 的地址:{0}", addr2); int code = info.GetHashCode(); Console.WriteLine("GetDearName 中哈希code:{0}", code); return dearName; } public static string GetMemory(object o) { GCHandle h = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection); IntPtr addr = GCHandle.ToIntPtr(h); return "0x" + addr.ToString("X"); } } }
通过运行结果,看以看出,当把另一个对象赋值给info时,main中的HashCode和GetDearName中info的HashCode不一致了,GetDearName中的info指向了另外一个对象,这将不满足把GetDearName中info的变化反应到Main中的info上了。这也就是ref的作用。
在GetDearName中的参数前面显示加上ref关键字,则表示传递的参数就是main中info的地址,没有重新分配栈地址。这样就算GetDearName中执行info=user,main中的info也会指向user这个对象,但是地址没有发生变化,把上面的GetDearName方法的参数前加上ref关键字,main调用中也加上,结果如下图
Mark下,如有不对之处,欢迎指出。
相关文章推荐
- C#中引用类型做方法参数时,加ref或out,与不加ref或out到底有什么区别?
- C#引用类型参数加ref或out与不加ref或out的区别
- 求教C#参数传递时,传递应用类型时,加不加ref的区别,有具体实例
- c#方法中调用参数的值传递方式和引用传递方式,以及ref与out的区别
- c#方法中调用参数的值传递方式和引用传递方式以及ref与out的区别深入解析
- C# 方法传参时,传入值类型、引用类型、string引用类型、ref修饰参数时分析
- c#方法中调用参数的值传递方式和引用传递方式,以及ref与out的区别
- C# 值类型和引用类型 以及作为方法参数的区别
- C#中ref、out类型参数的区别和params类型参数的用法
- 复习一下基础:'C# 值类型和引用类型 以及作为方法参数的区别'
- c#方法中调用参数的值传递方式和引用传递方式,以及ref与out的区别
- C#中ref、out类型参数的区别和params类型参数的用法
- C#引用类型参数,ref按引用传值
- C# 数据类型的引用类型、值类型内存存储方式以及区别; 函数参数传递的引用传递(址传递)、值传递区别
- c#方法中调用参数的值传递方式和引用传递方式,以及ref与out的区别
- C# 值类型 引用类型 作为参数传递区别
- C#中引用参数ref 、out的使用区别
- 引用类型参数使用ref与不使用ref的区别
- 实际举例C#引用类型和值类型的区别
- c#.net中参数修饰符ref,out ,params得区别