¿Cuándo se copia un valor / objeto de C # y cuándo se copia su referencia?

Sigo recibiendo el mismo problema una y otra vez cuando se copia un objeto al que quiero hacer referencia o cuando se hace referencia a un objeto que deseo copiar. Esto sucede cuando uso el operador =.

Por ejemplo, si estoy enviando el objeto a otra forma, es decir:

SomeForm myForm = new SomeForm(); SomeObject myObject = new SomeObject(); myForm.formObject = myObject; 

… y luego modifica el objeto en la forma, el objeto original no se modifica. Es como si el objeto se hubiera copiado y no se hubiera hecho referencia a él. Sin embargo, cuando hago esto:

 SomeObject myObject = new SomeObject(); SomeObject anotherObject = new SomeObject(); anotherObject = myObject; 

… y luego modifique anotherObject , anotherObject se modifica.

El caso más agravante es cuando trato de clonar uno de mis objetos definidos:

 public class SomeObject { double value1, value2; //default constructor here public SomeObject(val1, val2) { value1 = val1; value2 = val2; } public void Clone(SomeObject thingToCopy) { this.value1 = thingToCopy.value1; this.value2 = thingToCopy.value2; } } 

cuando hago esto …

 SomeObject obj1 = new SomeObject(1, 2); SomeObject obj2 = new SomeObject(); obj2.Clone(obj1); 

… se hace referencia a obj2 y cualquier modificación a obj2 cambia obj1 .

Los objetos del sistema como int, double, string , etc. parecen copiarse siempre, excepto en el caso del método de clonación anterior.

Mi pregunta es: no tener en cuenta el uso de la palabra clave ref en las funciones, cuándo se copia un objeto y cuándo se hace referencia a un objeto en cada caso (es decir, al pasar a funciones, al configurar como otros objetos (como los primeros dos ejemplos anteriores), al copiar variables miembro como el tercer ejemplo, etc.

Es difícil responder a este tipo de preguntas de manera precisa sin perder mucho tiempo eligiendo cuidadosamente sus palabras.

Lo he hecho en un par de artículos que pueden serle útiles:

  • Parámetro que pasa en C # / .NET
  • Tipos de referencia y tipos de valores en C # / .NET

Eso no quiere decir que los artículos sean perfectos, por supuesto, ni mucho menos, pero he intentado ser lo más claro posible.

Creo que una cosa importante es separar los dos conceptos (paso de parámetro y tipo de referencia frente a valor) en tu cabeza.

Para ver sus ejemplos específicos:

 SomeForm myForm = new SomeForm(); SomeObject myObject = new SomeObject(); myForm.formObject = myObject; 

Esto significa que myForm.formObject y myForm.formObject referencia a la misma instancia de SomeObject , como dos personas que tienen SomeObject de papel separadas, cada una con la misma dirección escrita. Si va a la dirección en una hoja de papel y pinta la casa de rojo, luego vaya a la dirección en la segunda hoja de papel, verá una casa roja.

No está claro a qué se refiere con “y luego modifica el objeto en el formulario” porque el tipo que ha proporcionado es inmutable. No hay forma de modificar el objeto en sí. Puede cambiar myForm.formObject para referirse a una instancia diferente de SomeObject , pero eso es como garabatear la dirección en una hoja de papel y escribir en ella una dirección diferente. Eso no cambiará lo que está escrito en la otra hoja de papel.

Si pudieras proporcionar un progtwig breve pero completo cuyo comportamiento no entiendas (idealmente una aplicación de consola, solo para que las cosas sean más cortas y simples) sería más fácil hablar de cosas en términos concretos.

Hola Mike Todos los objetos, que se derivan de ValueType, como struct u otros tipos primitivos son tipos de valores. Eso significa que se copian siempre que los asigne a una variable o los pase como un parámetro de método. Otros tipos son tipos de referencia, lo que significa que, cuando asigna un tipo de referencia a una variable, no es su valor, sino que su dirección en el espacio de la memoria se asigna a la variable. También debe tener en cuenta que puede pasar un tipo de valor como referencia utilizando la palabra clave ref. Aquí está la syntax

 public void MyMethod(ref int a) { a = 25 } int i = 20; MyMethod(ref i); //Now i get's updated to 25. 

Espero eso ayude 🙂

Con respecto a clonar sus objetos si los valores que está copiando de un objeto a otro son tipos de referencia, cualquier modificación a esos valores en el objeto original afectará los valores en el objeto copiado (ya que son solo referencias al mismo objeto)

Si necesita clonar un objeto que tiene propiedades que son tipos de referencia, necesita hacer que esos tipos sean clonables o hacer una copia manual de los mismos instanciando instancias nuevas según sea necesario.

Considere el uso de la interfaz IClonable , aunque no es la mejor solución.