Skip to content

引用和值传递

在值类型和引用类型中已经谈到过这类东西。但是这次再深入说说

方法参数

方法参数默认是按值传递的,可以看作是一种副本

  • 值类型就是传递一个值类型的副本
  • 引用类型就是传递一个引用(即对象地址)的副本

这样,作为局部变量的副本们,就会在函数体执行完毕之后被栈释放掉

由于值类型的传递比较简单,如果需要修改等,直接使用ref, out, in等关键字就好,已经在值类型和引用类型中提及,不再赘述。

考虑

假设有一个Person类型,封装了Name属性;我们需要修改它

C#
public void Modify(Person p) => p.Name = "Alice"

此时传入的p是对传入对象引用的拷贝,也就是说和原对象指向同一块堆区的内存空间,所以直接修改p,就会对原始数据产生影响

C#
public void Modify(Person p)
{
	Person temp = new("Alice");
	p = temp;
}

public void Modify(Person p) => p = new Person("Alice")

以上两种写法,都是把传入的副本p重新指向一块新的空间,这种写法是错误的,它并不会改变原始对象的引用所指向的位置(简单来说,这样写不会达到修改名字的效果)

方法被调用时,CLR 会把该引用的值复制一份到方法的参数槽里(这是参数的局部变量 p)。现在有两个引用值:调用方的引用仍然是 A,方法内部的 p 也是 A(但它们是两个独立的变量,存储相同的地址值)。

进行一个理解,假设原始引用是Person tom = new Person("Tom")

tom -> Person("Tom")

那么在调用方法的时候会出现 ——

tom, p -> Person("Tom")

也就是二者都指向同一块内存

现在执行函数体的时候

tom -> Person("Tom")
p   -> Person("Alice")

此时二者已经不是指向同一块地址了(tomtompp 所以并不相关,便可以解释此时对于p的修改并不会修改到tom所指向的数据

Released under the MIT License.