C#值类型和引用类型
与引用类型相对的是值类型。
值类型
当把一个值类型赋给另外一个时,就是对字段成员逐一进行复制,此时在栈上新建了值类型的两个副本,每一个都可以被独立操作。
引用类型
和栈中的值类型相比,当对引用类型应用赋值操作符时,我们就是在内存中重定向引用变量的指向。
其中,所有类实例都是引用类型。
按值传递引用类型
回顾一下形参和实参
在一般传值调用的机制中只能把实参传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参值发生改变,而实参中的值不会变化。而在引用调用的机制当中是将实参引用的地址传递给了形参,所以任何发生在形参上的改变实际上也发生在实参变量上。
参考:https://baike.baidu.com/item/形参/7677757?fr=aladdin
按值传递引用类型实例
假设有一个Person类,一个方法:void SendAPersonByValue(Person p)
void SendAPersonByValue(Person p){
//改变"p"的年龄
p.personAge = 99;
//调用者能看到这个重新赋值吗?
p = new Person("Nikki",99);
}
假设在Main()函数中,调用函数的代码如下:
Person fred = new Person("Fred",12);
SendAPersonByValue(fred);
结果显示,fred传进函数中后,他的personAge被改成了99(p.personAge = 99)
但是函数中的 p = new Person(“Nikki”,99);并未起作用。
结果解释
值传递方式下,形参是复制于实参的。
如果传入的是值类型,那很简单,就和预期一样,形参和实参完全没有关系。
而如果传入的是引用类型,那么会复制指向调用者对象的引用。
即p是一个引用变量,复制于传进来的fred变量,都指向了内存中的同一处,通过p改变该内存的值,fred引用也会看到变化,但是如果通过p 新建一份的内存区,那就和fred指向的内存区没有什么关系了。
按引用传递引用类型
如果把之前的函数改写成按引用传递引用类型,其形式如下:(C#语言)
void SendAPersonByValue(ref Person p){
//改变"p"的年龄
p.personAge = 99;
//fred引用变量也会受到影响,p和fred指向了堆上的一个新对象
p = new Person("Nikki",99);
}
此时,Main()函数中的fred引用变量也会受到影响
参考书籍:《精通C#(第六版)Andrew Troelsen》章节4.5