C#引用类型带ref关键字的用处

发布时间 2023-05-30 10:09:38作者: Yanaha

1.在C#中有两个大的数据类型,值类型和引用类型。

1)任何的结构体(例如:struct Int32...)或者是枚举都是值类型。

2)能被称作"类"的,则为引用类型,比如你用如下关键字(class、interface、delegate、record),或者是使用C#内置的引用类型:dynamic、object、string。

引用类型和值类型。 引用类型的变量存储对其数据(对象)的引用,而值类型的变量直接包含其数据。 对于引用类型,两种变量可引用同一对象;因此,对一个变量执行的操作会影响另一个变量所引用的对象。 对于值类型,每个变量都具有其自己的数据副本,对一个变量执行的操作不会影响另一个变量(inref 和 out 参数变量除外)-------- 引用类型 - C# 参考 | Microsoft Learn

 3)值类型放在栈上的,而引用类型是放在堆上的(new过之后),栈上只保留一个指向该引用类型的指针。

2.值类型方法形参的传递

1)对于值类型,传递的是该值的一个副本,在方法内部改变该值,对原有的值没有影响。如下例-> p最终打印出来还是1;

 1 static void Main(string[] args)
 2 {
 3       int p = 1;
 4 
 5       Add(p);
 6 
 7       Console.WriteLine(p);
 8       Console.ReadLine();
 9 }
10 static void Add(int x) => x += 1;

2)如果需要p能被方法内部所修改,则可以加上ref关键字来传递,对于值类型ref关键字会把该变量的地址传入,也就是传递一个指向该值的指针。如下例->p最终打印出来的是2;

 1   static void Main(string[] args)
 2   {
 3         int p = 1;
 4   
 5         Add(ref p);
 6   
 7         Console.WriteLine(p);
 8         Console.ReadLine();
 9   }
10  static void Add(ref int x) => x += 1;

 

     3.引用类型方法形参的传递

1)对于引用类型,引用类型的变量存储的是一个指向该变量值的指针。所以不用加ref关键字,就可以做到方法内部修改了值,传入的值也会变(但是无法改变传入值原有的引用)。下面打印出来的就是1\n2

static void Main(string[] args)
{
        MyClass mc = new()
        {
            id = 1,
            Type = "a"
        };
        Console.WriteLine(mc.id);
        Change(mc);
        Console.WriteLine(mc.id);
        Console.ReadLine();
}

 static void Change(MyClass mc)
{
         mc.id = 2;
}

 2)引用类型加上ref关键字传递,调用方则可以改变引用类型参数的引用。对象的存储位置按引用参数的值传递到方法,更改参数存储位置中的值(指向新对象),还可以将存储位置更改为调用方所引用的位置。如下例1,在方法内部改变了参数的原有对象引用,但是输出结果还是1\n2。

 1 static void Main(string[] args)
 2 {
 3         MyClass mc = new()
 4         {
 5             id = 1,
 6             Type = "a"
 7         };
 8         Console.WriteLine(mc.id);
 9         Change(mc);
10         Console.WriteLine(mc.id);
11         Console.ReadLine();
12 }
13 
14  static void Change(MyClass mc)
15 {
16          mc.id = 2;
17          mc = new()
18         {
19             id = 3,
20             Type = "c"
21         };
22 }

            如果加上ref传递,如下例2:最终打印的结果就是1\n3

 1   static void Main(string[] args)
 2   {
 3           MyClass mc = new()
 4           {
 5               id = 1,
 6               Type = "a"
 7           };
 8           Console.WriteLine(mc.id);
 9           Change(ref mc);
10          Console.WriteLine(mc.id);
11          Console.ReadLine();
12  }
13  
14   static void Change(ref MyClass mc)
15  {
16           mc.id = 2;
17           mc = new()
18          {
19              id = 3,
20              Type = "c"
21          };
22  }

总的来说如果参数是引用类型变量,内部可以操作该变量指向的内存的值(比如修改某个属性的值)但是无法修改该引用类型的原有对象引用(传递的),加上ref的传递则是把参数的指针传递了过来所以可以修改原对象引用。

eg:如果是方法的参数是引用类型,相当是有一个新的指针指向了该值内存空间。加上ref传递则是把原有的指针给传递了过来。