c# ref关键字对于引用类型传递的影响

我们可能见到下面的代码

public static void StringBuilderNoRef(StringBuilder s)     {

        s.Append(" World");

        s = new StringBuilder("hi");

    }

    public static void StringBuilderRef(ref StringBuilder s)     {

        s.Append(" World");

        s = new StringBuilder("hi");

    }

当我们先创建一个实例 StringBuilder s = new StringBuilder("Hello");

把s作为参数分别传递到两个方法的时候,我们会发现

输出结果是不一样的,一个是 Hello World,另一个是 hi

原因其实就是 在调用第一个方法的时候,传递了这个引用类型对象的引用的副本(不是对象本身),所以对于在调用方法外部的引用和方法中的引用来说,这两个引用都指向堆上的同一个对象。所以在修改此对象的属性值时,修改同时会应用于内部和外部的两个引用上。但重新分配其引用位置时,则只是修改副本引用的引用位置,原引用(方法外部)的位置不变,原引用还是指向原来的对象。
而如果加上Ref关键字,这时传入的参数则为些引用对象的原始引用,而不是引用的副本,这样的话,你就不但可以修改原始引用对象的内容,还可以再分配此引用的引用位置(用New 来重新初始化)。
如果你只想在方法中改变引用参数的内容,没有必要使用Ref来修饰引用参数。
如果你希望在方法中改变引用对象参数的引用(调用方法外的),如重新初始化对象,则需要使用Ref关键字来修饰参数。

下面我们再结合下图,阐述一下我理解的 实例 引用 对象 副本的区别和联系

  如图,new Person()是真正的对象是在堆内存里面,上图一共有3次new Person(),所以会在堆里面开辟3个空间,产生3个实例对象,每个对象之间都是相互独立的,使用自己的空间。而new Person()就是一个实例化的过程,将类Person生产出不同的对象。

  而等号的左边$p1是一个引用变量,通过赋值运算符“=”把对象的首地址赋给“$p1“这个引用变量,
所以$p1是存储对象首地址的变量,$p1放在栈内存里边,$p1相当于一个指针指向堆里面的对象, 所以我们可以通过$p1这个引用变量来操作对象,
通常我们也称对象引用为对象。

  其实一个对象就是一个实例,而引用是指一个存放对应首地址的对象,通过$p1这个引用变量来操作对象。

  副本则是拷贝了该引用的指针。

原文地址:https://www.cnblogs.com/wanglg/p/3455645.html