27

这些是我正在阅读的 ac# 书中的示例,只是在理解这个示例实际在做什么时遇到了一些困难,希望得到一个解释,以帮助我进一步了解这里发生的事情。

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

4 回答 4

60

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

例如,考虑一个典型的值类型,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只分配引用而不是值。so banda都指的是同一个对象。因此,在a.MyProperty = 2执行之后,b.MyProperty == 2因为ab引用同一个对象。


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

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 }在函数返回时看到新创建的对象。

于 2012-04-25T23:43:06.717 回答
14

术语的使用多么令人困惑!

澄清,

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

    但是,由于myArray它本身的“值”是一个副本,因此对该“值”的任何更改都不会影响原始对象或其内容。

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

于 2017-09-01T06:14:28.377 回答
7

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

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

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

于 2012-04-26T01:07:02.767 回答
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,x,x,..., ref test[x], ref test2, ... );
于 2021-01-10T00:48:58.967 回答