C#中参数为引用类型加ref和不加的区别

首先说说两种数据类型:值类型和引用类型的区别

值类型

包含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下,如有不对之处,欢迎指出。

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值