p1,p2都是自定义的Person类型,p1赋给p2后,p2的Age修改为20,p1的Age也收到了影响,这个可以理解
public static void Main(string[] args)
{
Person p1 = new Person();
Person p2 = new Person();
p1.Age = 18;
//Console.WriteLine(p1.Age);
p2 = p1;
p2.Age = 20;
Console.WriteLine(p1.Age);
Console.WriteLine(p2.Age);
Console.ReadLine();
}
但是请看下面的代码:
public static void Main(string[] args)
{
temps t = new temps();
Person p4 = new Person();
p4.Age = 50;
t.change(p4);
Console.WriteLine(p4.Age);
Console.ReadLine();
}
temps是另外定义的一个类,里面有一个change方法
public class temps
{
public void change(Person modle)
{
Person p3 = new Person();
p3.Age = 30;
modle = p3;
//Console.WriteLine(modle.Age);
}
}
将p4传入change方法后,把新New的p3的Age修改为30,然后给了传入的modle,最后p4输出的Age仍然还是
50,但是在change方法里面直接Console.WriteLine(modle.Age);却是30 想不通啊
change函数中是值传递
改成 public void change(ref Person modle) 试试
或者 public Person change 中return model
是啊,你传入把里面的值改了,并没有把改了的值传出去,楼上的可以
Person p4 = new Person();
p4存储在栈上,newParson()在堆上。
t.change(p4); 这里传的是p4的副本,而不是p4,虽然他们它们指向同一内存地址,但却是两个不同的引用。
也就是说如果在change()里面直接对modle(是model吧)进行操作,是会影响到p4的。
楼上的几位全部正解的,以ref形式按引用传递就可以的
在CLR中,只有当药运行某一个函数是才会分配内存空间,在lz中p3的生命周期是属于chang的,lz的方式就类似于浅复制,当离开chang时,就会被释放掉。如果将chang修改为:
public void change(Person modle)
{
Person p3 = modle;
p3.Age = 30;
//Console.WriteLine(modle.Age);
}我想应该行吧,没试过的。呵呵
呵呵,看来大家对C#的引用类型还没完全理解。在C++中函数调用分为 传值、传址、引用三种形式,其中后两种会对实参有影响。C++的引用和C#的引用是不一样的,这一点搞不清楚,你的程序运行起来和你想的可能就会不一致。
下面先说明一下C++的引用和C#的引用类型的区别,在C++中,引用可以理解为对象的别名,就像现实生活中一个人的大名和小名一样,其实都是一个人,C++通过引用进行调用本质就是对对象进行操作。但是C#的引用类型就不是这样的了,C#的引用本质是一个对象的地址,在函数调用的时候传递的是对象的地址,不需要创建对象副本,只需要复制对象的地址就可以了(这点一会实例证明一下),这也是C#相对高效的地方。由此我们可以看出:C#的引用类型对象的函数调用实际是地址,而C++是对象本身。
下面演示一下。
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 B b = new B();
6 A a1 = new A();
7 a1.Count = 10;
8 b.Change(a1);
9 Console.WriteLine(a1.Count);
10 Console.ReadLine();
11 }
12 }
13
14 class A
15 {
16 public int Count;
17 }
18
19 class B
20 {
21 public void Change(A a)
22 {
23 A temp = new A();
24 temp.Count = 50;
25 a = temp;
26 }
27 }
上面的代码调用后,输入的仍然是10.在调用过程中,Change(A a)中的a实际是把a的地址复制了一份传进去,因此无论怎么修改都不影响a.不信你可以在 a = temp;后面添加 a = null; 运行后还是10,不会出现错误的。C#要想传递对象本身,要使用 ref, 这样传入的实参就是对象本身,一旦进行 a = null;后,程序就会出现空引用错误。
下面证明一下C#引用类型在调用的时候没有发生复制构造。看程序:
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 B b = new B();
6 A a1 = new A(); //这里会调用一次
7 a1.Age = 10;
8 b.Change(a1); //这里如果是复制构造的话,Count会变成2,否则还是1
9 Console.WriteLine(A.Count);
10 Console.WriteLine(a1.Age);
11 Console.ReadLine();
12 }
13 }
14
15 class A
16 {
17 // Count 记录构造函数被调用的次数
18 public static int Count =0;
19
20
21 public A()
22 {
23 Count++;
24 Console.WriteLine("Count : {0}",Count);
25 }
26 public int Age;
27 }
28
29 class B
30 {
31 public void Change(A a)
32 {
33 a.Age = 1000;
34 }
35 }
我们知道声明类的时候如果没有构造函数,编辑器会默认生成一个,现在我们已经声明了一个,所以编辑器就不会再添加默认的了。
程序执行后, Count的值 一直是1.它发生在 A a1 = new A();的时候,而调用 Change(A a)的时候没有进行复制构造,Count值保持不变。
明白C#的引用类型之后就不会有疑惑了,希望能对你有帮助。
呵呵,其实不要想得很复杂
现在看你代码t.change(p4);
你这个没有返回值,可以说此时的p4相当于与一个{}中的作用域只在这个{}里,
而这个{}就是change(){}语句块,影响不了外部的变量
例如假设有这么个连续的语句
object a ;
public void (object b)
{
b=5;
} //但是b的作用域只有{}里面,出了{}谁认得他是谁的谁
就好比在啃老族家里成爷了,出了门还得装孙子。
没一点关系啊,明白了吧,没他们说的那么复杂。
可以这么说你在主语句块中加入个内部作用对外不影响的{}语句块等于脱裤子放屁多此一举,还把你想不通的。