Me he estado preguntando, ¿por qué mi método no modifica la matriz, cuando lo usé como parámetro y lo igualé a otra matriz con diferentes valores, dentro del método? ¿Solo estoy cambiando la dirección de referencia?
static void Main() { string[] array = { "yes", "no", "maybe" }; TestO(array); // Still "yes", "no", "maybe" } static void TestO(string[] array) { string[] secondArray = new string[array.Length]; secondArray[0] = "1"; secondArray[1] = "2"; secondArray[2] = "3"; array = secondArray; } Mi conjetura: no modifiqué la matriz dentro de Main(), porque al hacer array = secondArray; en el método Test0() , acabo de cambiar la dirección de referencia de la array a secondArray .
Si mi suposición no es correcta, mi pregunta es, ¿por qué exactamente no se modifica?
(Sé que puedo simplemente modificar Test0() a un método de retorno de string[] y devolver el secondArray modificado y pasarlo a la array en Main() )
Otra pregunta es: si uso el método de retorno string[] y declaro lo siguiente:
static void Main() { string[] array = { "yes", "no", "maybe" }; array = TestO(array); } static string[] TestO(string[] methodArray) { string[] secondArray = new string[methodArray.Length]; secondArray[0] = "1"; secondArray[1] = "2"; secondArray[2] = "3"; return secondArray; } array = TestO(array); ¿Solo estoy pasando la dirección de referencia de secondArray[] a array[] o estoy pasando solo sus valores? (Lo más probable es que sea la dirección de referencia, pero quería estar seguro si me equivoco)
no necesita devolver nada, solo use una referencia
static void Test( ref string[] array) { string[] secondArray = new string[array.Length]; secondArray[0] = "1"; secondArray[1] = "2"; secondArray[2] = "3"; array = secondArray; }Cuando pasas una matriz a un método
static void Test0(string[] array) {Está pasando una referencia a esa matriz. Esa referencia es efectivamente inmutable (obtiene una copia de la referencia, no la original), por lo que no puede cambiar la referencia del parámetro y esperar que afecte el código fuera del método de prueba.
Si bien puede hacer esto para obtener el comportamiento que desea:
static void Test0(ref string[] array) {no se considera un buen estilo C#. Las cadenas son en sí mismas inmutables; el estilo "correcto" es devolverlos desde el método. Esto también es cierto para las matrices de cadenas.
Lo único que ahorraría al usar esta técnica es una referencia adicional y una declaración de return , ya que de todos modos todavía está creando nuevas cadenas y una nueva matriz.
Acabo de cambiar la dirección de referencia de la matriz a secondArray. Si mi suposición no es correcta, mi pregunta es, ¿por qué exactamente no se modifica?
Creo que te inclinas a apreciar que hay dos referencias a un dato en la memoria (no hay dos datos); tienes una array variable que apunta a datos. Llamas a un método y otro, se establece la referencia de copia a los mismos datos. Hiciste un nuevo objeto, luego apuntaste la referencia copiada al nuevo objeto, dejando la referencia original apuntando a los datos originales, luego tiraste la referencia copiada y los nuevos datos. Estás de regreso exactamente en la misma situación en la que comenzó con
Pictóricamente, línea por línea, podría verse así (cambié el nombre del argumento de su método a arrayX para que la diferencia sea obvia):
Si decora el argumento con ref y lo llama con ref , no hay copia, por lo que el método llamado puede modificar la referencia original y señalarla en otro lugar:
Tenga en cuenta que en cualquiera de estos casos es perfectamente posible modificar el contenido de la matriz. Haciendo:
arrayX[0] = "New data"; ..tendría efecto en cualquier caso y la impresión array[0] mostraría "Nuevos datos". Al modificar los datos al final de la flecha no importa si el punto de partida es una referencia original o una copia. Esto se trata simplemente de si el método tiene el poder de señalar la referencia original que se le pasó, a un objeto diferente o no.
Generalmente no lo hacemos. Adoptamos el estilo de su segundo bloque de código: para devolver los datos. Puede ser útil verlo como algo grosero: imagina que tu amigo dice que cuidará de tu planta mientras estás de vacaciones; le das tus llaves a tu amigo. Te cambia la planta por otra que le gusta más; estas molesto porque tuviste esa planta por diez años..
Hay muy pocas razones para usar ref , o el "poder para sobrescribir su referencia" relacionado - out . No lo use para "Quería devolver varias cosas de mi método": en un mundo OO, siempre podemos devolver una cosa que represente dos elementos de datos. No necesitamos "devolver dos cosas"; podemos devolver una cosa con dos cosas dentro...
//don't: void GetPerson(ref string name, ref int age) //consider a class: Person GetPerson() return new Person(){ Name = ..., Age = ...} //or a Tuple (string Name, int Age) GetPersonDeje que el método de llamada elija si se debe sobrescribir su propia variable, en lugar de que un "tercero" tire de la alfombra debajo de sus pies.