c#参数值传递与引用传递的剖析

来源:互联网 发布:科比06赛季场均数据 编辑:程序博客网 时间:2024/04/29 12:41

引子:以两个人在两台机器的文件拷贝做例子,值传递好比是你把文件复制一份,通过网络传给他,然后他可以在他本机上对文件做任何的修改,修改会保存下来,但是你机器上的文件不会发生任何的变化。即形参与实参是两个不同的变量,各自占用不同的存储单元;地址传递好比是你把文件在网络上的地址告诉他人,他人通过网络访问你机器上的文件,他可以对文件进行修改并保存,此时,文件的内容就会发生变化。即形参与实参是相同的变量,占用同一段内存空间。

       传值的过程:
1)形参与实参各占一个独立的存储空间。
2)形参的存储空间是函数被调用时才分配的。调用开始,系统为行参开辟一个临时存储区,然后将各实参之值传递给形参,这时形参就得到了实参的值。
3)函数返回时,临时存储区也被撤销。

     传值的特点:单向传递,即函数中对形参变量的操作不会影响到调用函数中的实参变量。

地址传递过程:

参数是地址,实参和形参共享一个存储单元(也可以理解将实参的地址赋值给形参),对形参的操作相应的就改变了实参,此时参数传递是双向的。

Eg: 1(值类型的变量 进行值传递和引用传递)

using System;

public class PassParameter

{

public int val;

public static void Main(string[] args)

{

           PassParameter Test=new PassParameter();

           Test.val=100;

           Console.WriteLine("1.执行传递之前实参的值为:"+Test.val);

           TestPassParameter(Test.val); // 改成 TestPassParameter(Test.val);

           Console.WriteLine("2.执行传递之后实参的值为:"+Test.val);

}

public static void TestPassParameter(int tmpval)

// 上面改成public static void TestPassParameter(int tmpval)

{

           tmpval=200;

}

}

值传递结果100100(引用传递结果100200

利用引用类型变量进行值传递:传递是原引用变量的副本,即把原引用变量复制一份传递给方法,使得方法中的行参和实参引用的值相同,指向同一个对象的实例;引用类型变量是以对象引用的形式传递的,是将要传递的对象的引用复制给函数的形参,这时形参是实参引用的复制,注意:是引用的复制,而不是原引用,和原引用指向相同的对象,因此对于引用对象所做的更改将会直接影响原来的值,但是对于引用本身,在函数内的任何改变将不会影响原引用。

using System;

   class A
      {
         public string data="";
      }
      class Program
      {
          static void F( A a1)
          {
              //a1
指向传来的对象a              
              a1.data = "2";//
修改a1指向的对象
              a1 = new A();//a1
指向另一个对象,注意,这时a1已经不指向原来的对象a了,而原来的引用还是指向对象a
              a1.data = "3";//
修改新建的对象,不会影响原来对象a的值
          }
          static void Main()
          {
              A a = new A();//
实例化A的一个对象,并用a1指向该对象
              a.data = "1";//
adata字段赋值为"1"
              F(a);//
调用函数F,注意:这时将对象a的引用(不是对象a)赋值给参数a1,
              Console.WriteLine(a.data);
          }
      }

结果是2     而不是3也不是1.

利用引用类型参数进行引用传递:传递的是引用变量的引用,此时形参相当于是实参的一个别名,两者是同一个引用;对于已经是引用类型的参数,大家可能会说那不是多此一举吗?其实不然,因为其中的实机理完全不一样:

考查上个示例的变种

using System;

class A
      {
         public string data="";
      }
      class Program
      {
          static void F( ref A a1)
          {
            //a1
a是同一个实例,而不是指向同一对象的引用,即a1a在存在于内存中的地址是一样的
            a1.data = "2";//修改a1指向的对象
              a1 = new A();//a1
指向另一个对象,理所当然别名a也指向该对象了,注意,这时原来的对象已经没有任何引用指向了,因此,可以说原来的对象已经不可访问了。
              a1.data = "3";//
修改新建的对象的属性
          }
          static void Main()
          {
              A a = new A();//
实例化A的一个对象,并用a1指向该对象
              a.data = "1";//
adata字段赋值为"1"
            F(ref a);//
调用函数F,注意:这时将对象a的引用传给a1,不是赋值,相当于给a对象的引用起了个别名
             
Console.WriteLine(a.data);//这时a已经指向函数中新建的对象,因此值应为"3"
          }
      }

原创粉丝点击