按值和引用传递数组

这些是来自ac#book的例子,我正在阅读这个示例实际上正在做的一点点麻烦,想要一个解释来帮助我进一步了解这里发生的事情。

//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。

提前致谢

理解这一点的关键是要知道值类型和引用类型之间的区别。

例如,考虑一个典型的值类型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 == 2因为ab引用相同的对象。


考虑到你的问题中的代码,数组是一个引用类型,所以对于这个函数:

 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 }

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

数组是引用类型。 这意味着您按值传递引用。

只有在为其分配新数组时才会更改引用本身,这就是为什么这些赋值不会反映在调用者中的原因。 当您取消引用对象(此处的数组)并修改基础值时,您不会更改变量,只是指向它。 即使变量(即它指向的变量)保持不变,调用者也会“看到”这种变化。

多么令人困惑的用语!

澄清,

1)对于方法foo(int [] myArray),“按值传递引用(对象)”实际上意味着“传递对象地址(引用)的副本”。 这个’副本’的价值,即。 myArray,最初是原始对象的Address(引用),意味着它指向原始对象。 因此,myArray指向的内容的任何更改都将影响原始对象的内容。

但是,由于myArray本身的’value’是副本,因此对此’value’的任何更改都不会影响原始对象及其内容。

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