找回密码
 注册
搜索
热搜: java php web
查看: 934|回复: 30

[C#] 正确认识C#的引用传递,其实引用传递也是属于值传递

[复制链接]
发表于 2009-6-3 15:10:10 | 显示全部楼层 |阅读模式
以前一直误以为引用类型,在作为参数传递时,都是引用传递(类似于值传递中的ref),也就是说,把引用类型的变量作为参数传递给方法,在方法中修改该参数,会改变这个变量的值,
后来通过一些事例发现,上面的认识是片面的,引用类型传递实际上也是属于值传递的,只是引用类型传递的是一个堆地址。

先来个例子吧:
  • using System;
    public
    class test{

  • public
    static
    void Main(){        testClass a = new testClass();
  •         ChangeToNull(a);        Console.WriteLine(string.Format("a不是null,它的属性值为:{0}", a.field));

  •         ChangeField(a);
  •         Console.WriteLine(string.Format("a的属性值为:{0}", a.field));
  •         ChangeToNull(ref a);        Console.WriteLine(string.Format("a是不是null:{0}", (a == null)));
  •     }

  • static
    void ChangeToNull(testClass b){        b = null;

  • if(b == null){            Console.WriteLine("在ChangeToNull方法中,参数已经被修改成null了!");
  •         }    }


  • static
    void ChangeField(testClass b){
  •         b.field = 0;        Console.WriteLine("在ChangeField方法中,参数的成员已经被修改成0了!");
  •     }

  • static
    void ChangeToNull(ref testClass b){        b = null;

  • if(b == null){            Console.WriteLine("在ChangeToNull使用ref的重载方法中,参数已经被修改成null了!");
  •         }    }
  • }

  • class testClass{
    public
    int field;

  • public testClass(){        field = 123;
  •     }}


上面的代码,执行后的结果是:
在ChangeToNull方法中,参数已经被修改成null了!
a不是null,它的属性值为:123
在ChangeField方法中,参数的成员已经被修改成0了!
a的属性值为:0
在ChangeToNull使用ref的重载方法中,参数已经被修改成null了!
a是不是null:True


由此可见,引用类型作为参数时:
1、在修改变量本身时,结果类似于值传递,即不会改变传递前的变量的值
2、在修改变量的属性或字段时,才是引用传递,会影响到传递前的变量的值
3、参数使用了ref后,才是真正的引用传递,不管修改变量本身还是修改变量的属性或字段,都会影响到传递前的变量的值

究其原因,我们知道,值类型和引用类型,在运行时,它们存放的位置是不同的,值类型是存储在进程的栈上的
而引用类型是存储在进程堆(Heap)上的,在进程的栈上存储了这个引用类型在堆上的地址
而在调用方法时,是把栈上的参数的值复制一份传递给方法,所以值类型作为参数传递时,不会改变原变量值很明显
引用类型传递时,也是一样,把栈上的这个堆地址复制一份传递给方法,
所以在方法里修改这个复制的地址的值,当然不会改变原变量的值,
但是修改这个复制的地址所指向的堆里的内容,那原变量指向的地址的内容当然也跟着改变了。
如果参数加了ref,那传递的就是栈的地址的,此时不管是值类型还是引用类型,都会改变原变量的内容

综上所述,我们可以知道,引用类型作为参数传递,不能单纯的说它就是引用传递,如果直接这么认为,在开发中难免会犯错误的,深入的理解一下值类型和引用类型的传递,还是很有必要的。
发表于 2009-6-3 17:30:06 | 显示全部楼层
回复

使用道具 举报

发表于 2009-6-14 17:38:16 | 显示全部楼层
回复

使用道具 举报

发表于 2009-7-7 09:24:03 | 显示全部楼层
c#的资料好少。难道大家都不用c#?
回复

使用道具 举报

发表于 2009-7-22 21:40:15 | 显示全部楼层
回复

使用道具 举报

发表于 2009-7-23 14:57:15 | 显示全部楼层
实际中,C#对所有非简单类型的传递都是引用传递,楼主的认识是正确的,并非片面。只是对形参,实参这些概念有点模糊。任何情况下(传引用,传值)形参的改变,不会对实参有影响。
致于ref关键字,传递的内容实际是“实参”的引用。在C++或C中相当于是一个“指针的指针”。此时“形参”已经不是直接指向“实参”相同的地址,而是指着“实参”本身的地址,所以修改“形参”时,连带“实参”的引用也改变了。而且ref关键字传递参数时,传递的“实参”必需要先做初始化,至少为null。
回复

使用道具 举报

发表于 2009-8-6 12:10:38 | 显示全部楼层
回复

使用道具 举报

发表于 2009-8-21 22:43:01 | 显示全部楼层
懂了之后 怎么说都可以的
回复

使用道具 举报

发表于 2009-9-6 23:02:04 | 显示全部楼层
引用是根据地址
回复

使用道具 举报

发表于 2009-9-6 23:02:35 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|软晨网(RuanChen.com)

GMT+8, 2024-11-22 18:24

Powered by Discuz! X3.5

Copyright © 2001-2023 Tencent Cloud.

快速回复 返回顶部 返回列表