2012-04-25 15 views
10

Estos son ejemplos de un libro de C# que estoy leyendo solo teniendo un pequeño problema para comprender lo que este ejemplo está haciendo en realidad me gustaría una explicación que me ayude a comprender mejor lo que está sucediendo aquí.Pasando matrices por valor y por referencia

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

Básicamente no es el código de lo que me gustaría saber es que el libro está diciendo que si la matriz se pasa por valor de la llamada original no se modifican por el método (por lo que entiendo). Así que hacia el final del método FirstDouble intentan asignar una matriz de variables local a un nuevo conjunto de elementos que falla y los nuevos valores de la llamada original cuando se muestran son 2,4,6.

Ahora mi confusión es cómo hizo el bucle for en el método FirstDouble para modificar la llamada original firstArray a 2,4,6 si se pasaba por valor. Pensé que el valor debería seguir siendo 1,2,3.

Gracias de antemano

+0

posible duplicado de [Tipo de valor y problema del tipo de referencia] (http://stackoverflow.com/questions/6070892/value-type-and-reference-type-problem) –

+0

@AlexeiLevenkov Con esto cubierto tan bien en otro lugar, 'd odio a cerrar para que uno :( –

Respuesta

30

La clave para entender esto es saber la diferencia entre un value type and a reference type.

Por ejemplo, considere un tipo de valor típico, int.

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

Después de este código ha ejecutado, a tiene el valor 2, y b tiene el valor 1. Como int es un tipo de valor, b = a toma una copia del valor de a.

Consideremos ahora una clase:

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

Dado que las clases son los tipos de referencia, b = a simplemente asigna la referencia en lugar del valor. Entonces, b y a se refieren al mismo objeto. Por lo tanto, después de que se ejecute a.MyProperty = 2, b.MyProperty == 2 desde a y b consulte el mismo objeto.


Teniendo en cuenta el código en su pregunta, una matriz es un tipo de referencia y por lo tanto para esta función:

public static void FirstDouble(int[] array) 

la variable array es en realidad una referencia, porque int[] es un tipo de referencia. Entonces array es una referencia que es pasado por el valor.

Por lo tanto, las modificaciones realizadas en array dentro de la función se aplican realmente al objeto int[] al que se refiere array. Y esas modificaciones son visibles para todas las referencias que se refieren a ese mismo objeto. Y eso incluye la referencia que posee la persona que llama.

Ahora bien, si nos fijamos en la implementación de esta función:

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 }; 
} 

existe una complicación adicional. El bucle for simplemente duplica cada elemento del int[] que se pasa a la función. Esa es la modificación que ve la persona que llama.La segunda parte es la asignación de un nuevo objeto int[] a la variable local array. Esto no es visible para la persona que llama porque todo lo que hace es cambiar el destino de la referencia array. Y dado que la referencia array se pasa por valor, la persona que llama no ve ese nuevo objeto.

Si la función había sido declarado como esto:

public static void FirstDouble(ref int[] array) 

entonces la referencia array habría sido pasado por referencia y la persona que llama vería el objeto recién creado { 11, 12, 13 } cuando la función devolvió.

+0

Entonces, ¿cuál es la diferencia de hacer 'public void FirstDouble estática (ref matriz int [])'? – Jmyster

+0

@Jmyster mi última actualización cubre eso. –

+0

No No es correcto decir "la variable array es en realidad una referencia ". Eso significaría que asignarlo cambiaría el valor en la persona que llama al usar la terminología de llamada por referencia. Mantener este confuso término de" referencia "hace que sea difícil hablar de referencias en C++ o 'ref/out' en C#, que es por lo que obtiene mi -1. –

2

Todos los parámetros del método se pasan por valor a menos que específicamente se ve ref o out.

Las matrices son tipos de referencia. Esto significa que está pasando una referencia por valor.

La referencia en sí sólo se cambia cuando se asigna una nueva matriz a la misma, por lo que esas asignaciones no se reflejan en la persona que llama. Cuando quitas la referencia del objeto (la matriz aquí) y modificas el valor subyacente, no estás cambiando la variable, solo lo que apunta. Este cambio también será "visto" por la persona que llama, aunque la variable (es decir, lo que señala) permanece constante.

1

Qué confuso uso de términos!

Para aclarar,

1) para un foo método (int [] myArray) "pasando una referencia (objeto) por el valor" significa "que pasa una copia de la dirección del objeto (referencia)". El valor de esta 'copia', es decir. myArray, es inicialmente la dirección (referencia) del objeto original, lo que significa que apunta al objeto original. Por lo tanto, cualquier cambio en el contenido apuntado por myArray afectará el contenido del objeto original.

Sin embargo, puesto que el 'valor' de sí mismo miMatriz es una copia, cualquier cambio a este 'valor' no afectará al objeto original ni su contenido.

2) para un método foo (ref int [] refArray), "pasar una referencia (objeto) por referencia" significa "pasar la dirección del objeto (referencia) en sí (no una copia)". Eso significa que refArray es en realidad la dirección original del objeto en sí, no una copia. Por lo tanto, cualquier cambio en el 'valor' de refArray, o el contenido apuntado por refArray es un cambio directo en el objeto original en sí.

Cuestiones relacionadas