按值和引用传递数组

Tim*_*Tim 14 c# arrays

这些是来自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 };
Run Code Online (Sandbox Code Playgroud)

基本上有代码我想知道的是,本书说的是数组是否通过值传递,而不是原始调用者没有被方法修改(根据我的理解).因此,在方法FirstDouble结束时,他们尝试将局部变量数组分配给一组失败的新元素,并且显示原始调用者的新值为2,4,6.

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

提前致谢

Dav*_*nan 37

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

例如,考虑典型的值类型int.

int a = 1;
int b = a;
a++;
Run Code Online (Sandbox Code Playgroud)

执行此代码后,a其值为2,并b具有该值1.因为int是值类型,所以b = a取值的副本a.

现在考虑一个类:

MyClass a = new MyClass();
a.MyProperty = 1;
MyClass b = a;
a.MyProperty = 2;
Run Code Online (Sandbox Code Playgroud)

因为类是引用类型,所以b = a只分配引用而不是值.所以b,a两者都指向同一个对象.因此,在a.MyProperty = 2执行之后,b.MyProperty == 2因为a并且b引用相同的对象.


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

public static void FirstDouble(int[] array)
Run Code Online (Sandbox Code Playgroud)

变量array实际上是一个引用,因为它int[]是一个引用类型.所以array是一个基准按值传递.

因此,array对函数内部所做的修改实际上应用于int[]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 };
}
Run Code Online (Sandbox Code Playgroud)

还有一个复杂因素.该for循环简单加倍的每个元素int[]传递给函数.这是调用者看到的修改.第二部分是将新int[]对象赋值给局部变量array.这对调用者是不可见的,因为它只是改变了引用的目标array.并且由于引用array是按值传递的,因此调用者不会看到该新对象.

如果函数声明如下:

public static void FirstDouble(ref int[] array)
Run Code Online (Sandbox Code Playgroud)

然后引用array将通过引用传递,并且调用程序将{ 11, 12, 13 }在函数返回时看到新创建的对象.

  • @David 一遍又一遍地阅读你的回复后,我终于明白你在说什么了。这很令人困惑,但感谢您的详细解释,它确实很有帮助 (2认同)

Ser*_*rvy 7

除非您特别看到ref或 ,否则所有方法参数都是按值传递的out

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

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


小智 7

多么令人困惑的用语!

澄清,

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

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

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