阅读代码:
1 class Program
2 {
3 static void Main()
4 {
5 Person p1 = new Person { Name = "Andy" };
6 Person p2 = p1;
7
8 ModifyReferenceValue(p1);
9 ModifyReference(p1);
10 p1 = new Person { Name = "David"};
11 }
12
13 static void ModifyReferenceValue(Person p3)
14 {
15 p3.Name = "Bill";
16 }
17
18 static void ModifyReference(Person p4)
19 {
20 p4 = new Person { Name = "Carol" };
21 }
22 }
第5行:在栈上分配一个变量p1,p1的类型为Person;在堆上分配一个Person实例,该实例的Name为Andy;将P1 指向Andy实例。
第6行:在栈上分配一个变量p2,p2的类型为Person;将p1 赋值给p2;这时候p1,p2 都指向Andy实例。
第8行:调用方法ModifyReferenceValue;在栈上分配一个变量P3,P3的类型为Person;复制引用,将P1赋值给P3;此时P1,P2,P3都指向Andy实例;修改P3变量的值,实际上是修改P3指向的Andy实例,将Andy实例的Name修改为Bill;由于P1,P2,P3的Name都是Bill;方法调用结束,释放P3在栈上的内存。
第9行:调用方法ModifyReference;在栈上分配一个变量P4,P4的类型为Person;复制引用,将P1赋值给P4;此时P1,P2,P4都指向Bill实例;修改P4,使它指向在堆上刚刚创建的Carol实例;此时,P4指向Carol实例,P1,P2仍然指向Bill实例;方法调用结束;释放P4在栈上的内存;这时候没有引用指向Carol实例,GC会在合适的时机,回收堆上的Carol实例;
第10行:修改P1,使它指向在堆上刚刚创建的David实例;此时P1指向David实例,P2仍然指向Bill实例。
总结:在调用方法传递参数的过程中:
1、如果参数是值类型,由于值类型是“整体拷贝”,对值类型的修改只在当前方法范围内有效,不会影响到外部。调用方法结束后,在栈上弹出,不会产生副作用。
2、如果参数是引用类型并且修改引用的值,由于引用类型是“复制引用”,修改引用的值,将产生副作用。与当前引用 指向实例相同的引用都会变化。
3、如果参数是引用类型并且修改引用使之指向其他的实例,不会产生副作用。
因此,需要注意 修改引用的值 与 修改引用的区别。