按值和引用传递数组

时间:2012-04-25 23:39:44

标签: c# arrays

这些是我正在阅读的一本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。

提前致谢

4 个答案:

答案 0 :(得分:36)

理解这一点的关键是要了解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所做的修改实际上应用于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 };
}

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

如果函数声明如下:

public static void FirstDouble(ref int[] array)

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

答案 1 :(得分:5)

多么令人困惑的用语!

澄清,

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

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

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

答案 2 :(得分:4)

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

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

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

答案 3 :(得分:0)

为您提供实现逻辑的 .net 开源知识的想法;

//Sample Code, Illustration;
Method1(params dynamic[] var1) {
  var1[0]=new dynamic[3] { 1,2,3 }
}

var1 未指定或不能为 ref ? 一个使用场景是......

//Sample Code, Illustration;
dynamic[] test = new dynamic[];
Method1( ref test,x,x,x,x  );
System.Windows.MessageBox.Show( test[2].ToString() );

仅在何时指示 ref,而不是特定于参数; 以及对数组项的引用;

//result is IndexOutOfBounds;

这只是一个说明,它可以通过返回一个数组来完成并使用:

test = Method1( test,... );

而不是:

Method1( ref test,... );