c#引用传递,值传递,引用传递实际上也是属于值传递

16 篇文章 0 订阅
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int num = 0;
            Person p = new Person("Li");
            A1( p, num);
            //A1(ref p,num);
            Console.WriteLine("{0},{1}", p.name, num);
            Console.Read();
        }
        static void A1( Person p1, int num)
        {
           // p1 = new Person("Wang");
            p1.name = "Wang";
            num = 1;
        }
    }
    public class Person
    {
        public string name;
        public Person(string name)
        {
            this.name = name;
        }
    }
}

P是以引用形式传进来的,num是以值形式传进来的,所以在Al()中对num的修改不会返回到调用Al()的函数中; 
Al()函数中的p是引用,所以对P的修改会影响p的值,但引用也是复制后传到Al()函数中的,所以对P的副本重新赋值不会影响到p,但对p副本的属性赋值会影响到p,这大概就是引用;
这里的p已经不是原始的P。原来的如果是P1的话,这个就当作P2吧。
P1和P2都是引用,他们指向的对象都是一样的,设为obj吧。
如果用p.name="wang",就直接修改了所指向的对象obj。
而p=new Person("Wang"),则是创建了新的对象obj2,然后把p2指向obj2。

//static void Main(string[] args)
//{
//    int num = 0;
//    Person p = new Person("Li");
//    string name = p.name;
//    A1(p, name, num);
//    Console.WriteLine("{0},{1},{2}", p.name, name, num);//结果应该是 Wang,Li,0...
//}

//static void A1(Person p, string name, int num)
//{
//    name = "Wang";//按值传递的引用类型参数不可更改...
//    p.name = name;//按值传递的引用类型参数其成员可更改...
//    num = 1;//按值传递的值类型参数不可更改...
//}

以前一直误以为引用类型,在作为参数传递时,都是引用传递(类似于值传递中的ref),也就是说,把引用类型的变量作为参数传递给方法,在方法中修改该参数,会改变这个变量的值,

后来通过一些事例发现,上面的认识是片面的,引用类型传递实际上也是属于值传递的,只是引用类型传递的是一个堆地址。

 

先来个例子吧:

  1. using System;
  2. public class test{
  3.     public static void Main(){
  4.         testClass a = new testClass();
  5.         ChangeToNull(a);
  6.         Console.WriteLine(string.Format("a不是null,它的属性值为:{0}", a.field));
  7.         
  8.         ChangeField(a);
  9.         Console.WriteLine(string.Format("a的属性值为:{0}", a.field));
  10.         ChangeToNull(ref a);
  11.         Console.WriteLine(string.Format("a是不是null:{0}", (a == null)));
  12.     }
  13.     
  14.     static void ChangeToNull(testClass b){
  15.         b = null;
  16.         if(b == null){
  17.             Console.WriteLine("在ChangeToNull方法中,参数已经被修改成null了!");
  18.         }
  19.     }
  20.     
  21.     static void ChangeField(testClass b){
  22.         b.field = 0;
  23.         Console.WriteLine("在ChangeField方法中,参数的成员已经被修改成0了!");
  24.     }
  25.     
  26.     static void ChangeToNull(ref testClass b){
  27.         b = null;
  28.         if(b == null){
  29.             Console.WriteLine("在ChangeToNull使用ref的重载方法中,参数已经被修改成null了!");
  30.         }
  31.     }
  32. }
  33. class testClass{
  34.     public int field;
  35.     public testClass(){
  36.         field = 123;
  37.     }
  38. }

上面的代码,执行后的结果是:

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

由此可见,引用类型作为参数时:

1、在修改变量本身时,结果类似于值传递,即不会改变传递前的变量的值

2、在修改变量的属性或字段时,才是引用传递,会影响到传递前的变量的值

3、参数使用了ref后,才是真正的引用传递,不管修改变量本身还是修改变量的属性或字段,都会影响到传递前的变量的值

 

究其原因,我们知道,值类型和引用类型,在运行时,它们存放的位置是不同的,值类型是存储在进程的栈上的

而引用类型是存储在进程堆(Heap)上的,在进程的栈上存储了这个引用类型在堆上的地址

而在调用方法时,是把栈上的参数的值复制一份传递给方法,所以值类型作为参数传递时,不会改变原变量值很明显

引用类型传递时,也是一样,把栈上的这个堆地址复制一份传递给方法,

所以在方法里修改这个复制的地址的值,当然不会改变原变量的值,

但是修改这个复制的地址所指向的堆里的内容,那原变量指向的地址的内容当然也跟着改变了。

如果参数加了ref,那传递的就是栈的地址的,此时不管是值类型还是引用类型,都会改变原变量的内容

 

综上所述,我们可以知道,引用类型作为参数传递,不能单纯的说它就是引用传递,如果直接这么认为,在开发中难免会犯错误的,深入的理解一下值类型和引用类型的传递,还是很有必要的。

 

 

详细链接:http://blog.csdn.net/youbl/article/details/3338378

http://topic.csdn.net/u/20090402/14/1127eb2a-3693-4d2c-8705-18c08e216177_3.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值