2012-04-25 168 views
10

这些是我正在阅读的一本c#书籍中的示例,它只是为了解这个示例实际正在做的事情而有点麻烦,希望能够帮助我进一步理解这里发生的事情。通过数值和引用传递数组

 //creates and initialzes firstArray 
     int[] firstArray = { 1, 2, 3 }; 

     //Copy the reference in variable firstArray and assign it to firstarraycopy 
     int[] firstArrayCopy = firstArray; 

     Console.WriteLine("Test passing firstArray reference by value"); 


     Console.Write("\nContents of firstArray " + 
      "Before calling FirstDouble:\n\t"); 

     //display contents of firstArray with forloop using counter 
     for (int i = 0; i < firstArray.Length; i++) 
      Console.Write("{0} ", firstArray[i]); 

     //pass variable firstArray by value to FirstDouble 
     FirstDouble(firstArray); 

     Console.Write("\n\nContents of firstArray after " + 
      "calling FirstDouble\n\t"); 

     //display contents of firstArray 
     for (int i = 0; i < firstArray.Length; i++) 
      Console.Write("{0} ", firstArray[i]); 

     // test whether reference was changed by FirstDouble 
     if (firstArray == firstArrayCopy) 
      Console.WriteLine(
       "\n\nThe references refer to the same array"); 
     else 
      Console.WriteLine(
       "\n\nThe references refer to different arrays"); 

     //method firstdouble with a parameter array 
     public static void FirstDouble(int[] array) 
    { 
     //double each elements value 
     for (int i = 0; i < array.Length; i++) 
      array[i] *= 2; 

     //create new object and assign its reference to array 
     array = new int[] { 11, 12, 13 }; 

基本上没有,我想知道是什么代码是,如果阵列由值比原来的调用者传递没有得到通过方法(据我所知)修改书说。因此,在方法FirstDouble结束时,他们尝试将局部变量数组分配给一组失败的元素,并在显示时原始调用方的新值为2,4,6。

现在我的困惑是,方法FirstDouble中的for循环如何将原始调用方firstArray修改为2,4,6(如果它是通过值传递的)。我认为价值应该保持在1,2,3。

在此先感谢

+0

可能重复的[值类型和引用类型问题](http://stackoverflow.com/questions/6070892/value-type-and-reference-type-problem) – 2012-04-25 23:50:11

+0

@AlexeiLevenkov在其他地方覆盖如此之好,我'd讨厌关闭那一个:( – 2012-04-26 00:10:34

回答

30

理解这一点,关键是要知道一个value type and a reference type之间的区别。

例如,考虑一个典型的值类型,int

int a = 1; 
int b = a; 
a++; 

此代码已被执行之后,a具有值2,并且b具有值1。由于int是值类型,因此b = a需要a的值的副本。

现在考虑一类:

MyClass a = new MyClass(); 
a.MyProperty = 1; 
MyClass b = a; 
a.MyProperty = 2; 

因为类是引用类型,b = a仅仅分配的参考,而不是价值。所以ba都指向同一个对象。因此,执行a.MyProperty = 2后,b.MyProperty == 2ab表示相同的对象。


考虑在你的问题的代码,阵列是用于此功能的基准型等:

public static void FirstDouble(int[] array) 

可变array实际上是一个参考,因为int[]是引用类型。所以array参考通过值

因此,在功能内对array所做的修改实际上应用于array所涉及的int[]对象。所有这些修改对于引用同一对象的所有引用都是可见的。这包括调用者持有的引用。现在

,如果我们看一下这个函数的实现:

public static void FirstDouble(int[] array) 
{ 
    //double each elements value 
    for (int i = 0; i < array.Length; i++) 
     array[i] *= 2; 

    //create new object and assign its reference to array 
    array = new int[] { 11, 12, 13 }; 
} 

有一个进一步复杂化。 for循环只是将传递给函数的int[]的每个元素加倍。这是调用者看到的修改。第二部分是将新的int[]对象分配给本地变量array。这对调用者不可见,因为它所做的只是更改参考array的目标。并且由于参考array是按值传递的,因此调用者不会看到该新对象。

如果函数已经声明如下:

public static void FirstDouble(ref int[] array) 

则引用array会被通过引用传递和调用者会看到新创建的对象{ 11, 12, 13 }当函数返回。

+0

那么与做'公共静态无效FirstDouble(ref int []数组)'' – Jmyster 2012-04-25 23:46:00

+0

@Jmyster我的最新更新涵盖了什么? – 2012-04-25 23:49:46

+0

否这是错误的说“变量数组实际上是一个引用“,这意味着当使用引用引用术语时,赋值给它会改变调用者的值,保留这个引用的混淆术语使得很难谈论C++中的引用或''ref/out'在C#中,这就是为什么它得到我-1. – 2012-04-25 23:55:07

2

除非您明确看到refout,否则所有方法参数都按值传递。

数组是参考类型。这意味着您正在通过值传递参考。

引用本身只在您为其分配新数组时才会更改,这就是为什么这些分配未反映到调用者中的原因。当你去引用对象(数组在这里)并修改底层的值时,你并没有改变变量,只是它指向的是什么。即使变量(即指向的内容)保持不变,调用者也会“看到”此更改。

1

这是多么令人费解的术语使用!

为了澄清,

1)一种方法foo(INT [] myArray的), “按值传递一个参考(对象)”,实际上是指 “通过对象的地址的拷贝(参考)”。这个'复制'的价值,即。 myArray,最初是原始对象的地址(引用),意思是它指向原始对象。因此,对myArray指向的内容所做的任何更改都会影响原始对象的内容。

但是,由于myArray本身的'值'是副本,所以对'值'的任何改变都不会影响原始对象或其内容。 2)对于方法foo(ref int [] refArray),“通过引用传递引用(对象)”意味着“传递对象的地址(引用)本身(不是副本)”。这意味着refArray实际上是对象本身的原始地址,而不是副本。因此,对refArray的'value'或refArray所指向的内容的任何改变都是对原始对象本身的直接改变。