首页 新闻 会员 周边

C#引用类型的问题!!!

0
悬赏园豆:50 [待解决问题]

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 想不通啊

       

zuohuiming的主页 zuohuiming | 初学一级 | 园豆:6
提问于:2011-08-15 20:12
< >
分享
所有回答(7)
0

change函数中是值传递
改成 public
void change(ref Person modle) 试试
或者  public Person change 中return model 

慧☆星 | 园豆:5640 (大侠五级) | 2011-08-16 08:56
0

是啊,你传入把里面的值改了,并没有把改了的值传出去,楼上的可以

蓦然回首的思念 | 园豆:900 (小虾三级) | 2011-08-16 09:45
1

Person p4 = new Person();

p4存储在栈上,newParson()在堆上。

t.change(p4);  这里传的是p4的副本,而不是p4,虽然他们它们指向同一内存地址,但却是两个不同的引用。

也就是说如果在change()里面直接对modle(是model吧)进行操作,是会影响到p4的。

写代码的小2B | 园豆:4371 (老鸟四级) | 2011-08-16 12:54
0

楼上的几位全部正解的,以ref形式按引用传递就可以的

雪纷飞 | 园豆:190 (初学一级) | 2011-08-16 16:20
1

在CLR中,只有当药运行某一个函数是才会分配内存空间,在lz中p3的生命周期是属于chang的,lz的方式就类似于浅复制,当离开chang时,就会被释放掉。如果将chang修改为:

public void change(Person modle)
{
Person p3
= modle;
p3.Age = 30;
//Console.WriteLine(modle.Age);

}我想应该行吧,没试过的。呵呵
yangtam | 园豆:369 (菜鸟二级) | 2011-08-22 15:55
0

呵呵,看来大家对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#的引用类型之后就不会有疑惑了,希望能对你有帮助。

归真 | 园豆:605 (小虾三级) | 2011-10-18 16:37
0

呵呵,其实不要想得很复杂

现在看你代码t.change(p4);

你这个没有返回值,可以说此时的p4相当于与一个{}中的作用域只在这个{}里,

而这个{}就是change(){}语句块,影响不了外部的变量

例如假设有这么个连续的语句

          object a ;

          public  void (object  b)

         {

              b=5;

          }  //但是b的作用域只有{}里面,出了{}谁认得他是谁的谁

        就好比在啃老族家里成爷了,出了门还得装孙子。

没一点关系啊,明白了吧,没他们说的那么复杂。

可以这么说你在主语句块中加入个内部作用对外不影响的{}语句块等于脱裤子放屁多此一举,还把你想不通的。

Halower | 园豆:1723 (小虾三级) | 2012-04-02 18:24
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册