Pass by value & pass by reference

来源:互联网 发布:小站托福怎么下载mac版 编辑:程序博客网 时间:2024/04/30 02:24

CR: http://blog.sina.com.cn/s/blog_499e0a9101000527.html



学过C#的人都知道,通过值或通过引用,值类型和引用类型都可以作为方法参数传递。在C#中,不管是值类型或者是引用类型,所有方法参数在默认情况下是通过值传递的。而在Visual Basic 6中,默认通过引用传递参数。
   对于值类型和引用类型来说,通过值传递有不同的含义。以下将分别进行叙述:
1)通过值传递值类型
   在通过值传递作为方法参数的变量时,传递给方法的是数据副本。在方法中对该数据的任何修改都不会对初始值有任何影响。
   在下面的Visual Basic程序中:
   Private Sub Form_Load()
      Dim value as integer
      value=50
      DoSomething value
      MsgBox value
   End Sub
   Public Sub DoSomething(parameter As Integer)
      parameter=100
   End Sub
   在执行时,这个程序将显示一个包含值为100的消息框。这说明了在DoSomething方法中改变值会影响在Form_Load中定义的初始变量。这也就意味着改值是通过引用传递的。现在如果改变DoSomething的定义如下:
    Public Sub DoSomething(ByVal parameter Integer)
现在弹出的消息框显示值为50,这次参数是通过值传递的,意味着值的副本是传递给子例程的,而不是初始变量的引用。
    在默认情况下,Visual Basic6 通过引用传递参数,而C#通过值。看如下代码:
    using System;
    class MyExecutableClass
    {
       static void Main(string[] args)
         {
            int value=50;
            DoSometing(value);
            Console.WriteLine(value);
         }
        
        static void DoSomething(int parameter)
         {
             parameter=100;
         }
    }
    程序的输出为50.也许你会感到奇怪,为什么不是100呢?因为变量value是通过值而不是引用传递的。我们不需要添加任何特殊的关键字,而是依赖于C#的默认行为,通过值传递值类型。
  2)通过引用传递值类型
    通过引用传递值类型,也就是说传递值(变量)的引用。如果传递引用的话,那么无论在程序的什么地方作改变的话(可能是在另一个方法、属性中,甚至是另一个对象中),都会改变使用改引用的值。对方法中任何参数的改变都将影响方法的返回值。
    在C#中,通过引用传递是通过ref关键字实现的,必须按如下所示将ref关键字添加到方法定义中:
       static void DoSomething(ref int parameter)
    在传递参数时,必须使用ref关键字。
       DoSomething(ref value)
    下面的代码演示了如何对值类型使用ref关键字:
 using System;
 class MyExecutableClass
   {
     static void Main(string[] args)
       {
          int value=50;
          DoSomething(ref value);
          Console.WriteLine(value);
       }
     static void DoSomething(ref int parameter)
       {
          parameter=100;
       }
   }
结果正如你所料,输出为100.
3)通过值传递引用类型
   一般来说,通过值传递意味着传递存储在栈中的值。对于引用类型来说,存储在栈上的值表示对
内存中对象实际位置的引用。因此,如果通过值传递引用类型,就意味着传递的是对象的引用(它的堆栈)
.使用该引用作的改变最终会改变堆中的同一对象。
   通过值传递引用类型不像通过值传递值类型---它更像通过引用传递值类型。在如下代码中,
我们将Person用作引用类型。
using System;
class MyExecutableClass
  {
    static void Main(string[] args)
     {
        Person person=new Person(50);
        DoSomething(person);
        Console.WriteLine(person.Age);
     }
    static void DoSomething(Person somePerson)
     {
        somePerson.Age=100;    
     }
  }
class Person
   {
     public int Age;
     public Person(int Age);
      {
        this.Age=Age;
      }
   } 
     运行程序,可以发现输出值为100.如果对DoSometing方法作如下修改;
   static void DoSomething(Person somePerson)
   {
      somePeron=new Person(100);
   }
     重新运行程序,发现输出为50.这是因为我们并没有将引用传递给方法?
     答案是:不,我们确实发送了引用。引用类型有两个元素---引用和对象。现在,在
调用DoSomething()方法时,我们创建了一个引用副本,它仍然指向同一对象,因此,对对象的改变会影响主程序。而对引用的改变则不会,在方法结束时,消失的只是引用的副本。
     在使用somePerson.Age属性改变年龄时,我们改变的是对象。但接下来是创建一个新对象,改变引用来指向它---对引用的改变将会丢失。
     应该怎么做呢?方案就是通过引用传递引用类型,那样作的话,如果改变somePerson所存储的引用,那么另一个“父”引用会自动更新。听起来很混乱,下面再讨论。
4) 通过引用传递引用类型
     我们知道,在通过值传递引用类型时,我们传递对内存中对象位置的引用。而通过引用传递引用类型时,我们将传递引用的引用。   
  正如我们所看到的,通过值传递引用类型并不适合于所有情况---特别是需要改变引用以指向新对象时。
     下面例子就是说明通过引用传递就很有用。
 using System;
 class MyExecutableClass
 {
  static void Main(string[] args)
   {
     Person person=new Person(50);
     DoSometing(ref person);
     Console.WriteLine(person.Age);
   }
  static void DoSometing(ref Person somePerson)
   {
     somePerson=new Person(100);
   
   
    这次输出为100;person变量实际上对堆上Person对象的引用。在调用DoSomething()时,编译器创建了对Person引用的引用(而不是对Person对象的引用).在DoSometing()方法中,somePerson是Person引用的引用,而Person引用堆上的对象。然而,DoSomething()知道值是通过引用传递的,因此对somePerson的任何改变实际上是改变了person。结果就是somePerson的行为就好像它是person引用,而不是其副本。

原创粉丝点击