Cuando es un C# value/objeto copiado y cuando es su referencia copiado?

Sigo teniendo el mismo problema una y otra vez donde un objeto de deseo de referencia es copiado o cuando un objeto que desea copiar se hace referencia. Esto sucede cuando puedo usar el operador=.

Por ejemplo, si yo voy a enviar el objeto a otro formulario, es decir:

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

…y, a continuación, modificar el objeto en la forma, el objeto original no conseguir modificado. Es como si el objeto fue copiado y no se hace referencia. Sin embargo, cuando hago esto:

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

…y, a continuación, modificar anotherObject, myObject se modificó así.

La mayoría de los agravantes del caso es que al intentar 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);

obj1 es la referencia, y cualquier modificación a obj2 cambios obj1.

Sistema de los objetos, tales como int, double, string, etc siempre parecen ser copiado, salvo en el caso de el clon método anterior.

Mi pregunta es, no teniendo en cuenta el uso de la ref palabra clave en funciones, cuando no un objeto se copian, y cuando un objeto se hace referencia en cada caso de la materia (es decir, cuando se pasa a las funciones, al establecer como otros objetos (como en los primeros dos ejemplos anteriores), cuando la copia de los estados de variables como el tercer ejemplo, etc.)?

InformationsquelleAutor Mike Webb | 2010-12-03

3 Kommentare

  1. 48

    Es difícil contestar este tipo de preguntas con precisión sin tener que gastar un montón de tiempo escogiendo sus palabras cuidadosamente.

    He hecho en un par de artículos que usted puede encontrar útil:

    Eso no quiere decir que los artículos son perfectos, por supuesto – lejos de ello -, pero he tratado de ser tan claro como sea posible.

    Creo que una cosa importante es separar los dos conceptos (transferencia de parámetros de referencia y vs tipos de valor) en su cabeza.

    Mirar sus ejemplos específicos:

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

    Esto significa que myForm.formObject y myObject se refieren a la misma instancia de SomeObject – como dos personas que tienen distintos trozos de papel, cada uno con la misma dirección escrita en ellos. Si usted va a la dirección en un pedazo de papel y pintura de la casa roja, a continuación, vaya a la dirección que aparece en la segunda pieza de papel, verás una casa roja.

    No está claro qué quiere decir con «y a continuación, modificar el objeto en el formulario» porque el tipo que usted ha proporcionado es inmutable. No hay manera de modificar el objeto en sí mismo. Usted puede cambiar myForm.formObject para referirse a una instancia diferente de SomeObject, pero eso es como escribir la dirección en un pedazo de papel y escribir una dirección diferente en su lugar. Que no va a cambiar lo que está escrito en el otro pedazo de papel.

    Si usted puede proporcionar un corto pero completa programa cuyo comportamiento no entiende (lo ideal es una aplicación de consola, sólo para mantener las cosas más corto y más sencillo) sería más fácil hablar de las cosas en términos concretos.

    • Voy a tener que escribir uno. Entiendo punteros para la mayor parte de C++, yo no entiendo cuando se usa en relación con el valor de referencia y los tipos en C# como no hay ninguna explícita «seguro» puntero de uso/operadores en C#.
    • Voy a escribir el programa, más tarde, como ahora estoy en el trabajo. Gracias por la ayuda. Voy a leer los artículos.
    • La analogía de la dirección, en hojas separadas de papel es útil para comprender el concepto de los tipos de referencia.
    • Skeet: Siento ser quisquilloso, cuando probé el ejemplo en el segundo enlace (los tipos de Referencia y el valor de los tipos en C# / .NET) me di cuenta de que «.Texto» está a la izquierda de la Consola».WriteLine («originalPrintedPage={0}»,originalPrintedPage);»
    • Gracias por decírmelo. Fija ahora!
    • Jon, ¿puede por favor explicar cómo en bajo nivel by value la copia se hace? ¿CLR utilizar algún tipo de reflexión y copia de campo por campo? O simplemente copias el área de memoria?
    • ¿Para qué tipo de tipo? Para los tipos de referencia, es solo la copia de la referencia – un puntero, efectivamente. Los tipos de valor, creo que hay más sutileza involucrados, pero aún así, básicamente, la copia de un fragmento de memoria. No es necesario el uso de la reflexión – se sabe lo grande que es el tipo, y donde el valor está en la memoria.
    • gracias por un responderle. ¿Recuerdas algún artículo sobre este tema con bajo nivel de detalles? Me gustaría leer más.
    • No, no de improviso, me temo.
    • No estoy seguro si el OP ha compartido algo de código y este post es bastante antiguo sé. Pero tengo algunas código cuyo comportamiento parecer extraño, no se si abrir un post nuevo o contribuir a esta. El código está aquí: pastie.org/10785292
    • No parece extraño para mí – r no puede ser una referencia, ya que su tipo es SearchResultEntry.
    • la elección de una escueta respuesta fue en sí mismo informativo, sugirió que mis ojos han sido ciegos a algo de pie justo en frente de ellos. Miré hacia SearchResultEntry y sólo ahora se dan cuenta de que no está definido como un class pero como struct y, como tal, es un tipo de valor. Obviamente r no puede ser una referencia. Gracias Jon.

  2. 7

    Hola Mike
    Todos los objetos, que se deriva de ValueType, tales como la estructura o de otros tipos primitivos son tipos de valor. Eso significa que ellos se copian cada vez que se les asigne a una variable o les pasa como un parámetro de método. Otros tipos son tipos de referencia, lo que significa que, al asignar un tipo de referencia a una variable, no es un valor, sino la dirección en el espacio de memoria asignado a la variable.
    También se debe tener en cuenta que se puede pasar de un tipo de valor como referencia de uso de palabra clave ref. He aquí la sintaxis

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

    Espero que ayude 🙂

    • Siento ser quisquilloso aquí. Los objetos no se derivan. Tipos de hacer. Objeto general es el término utilizado para describir una instancia de un tipo.
    • Se puede pasar un argumento de por referencia mediante ref, pero que no es lo mismo que pasa es que como una referencia. Creo que es importante diferenciar entre los dos.
    • Sé que esta es una vieja pregunta, pero se puede aclarar o compartir alguna información acerca de tu último comentario? Me refiero a pasar por de referencia vs pasando como de referencia? gracias de antemano 🙂 yo estoy pidiendo desde siempre he pensado que tanto va a terminar con el mismo resultado que está afectando el pasado objeto de valor si es que pasa dentro de un método externo.
    • Es probablemente el mejor que se acaba de leer jonskeet.uk/csharp/parameters.html
    • gracias por la rápida respuesta, su próxima taza de café está en mí 😉
  3. 1

    Con respecto a la clonación de los objetos si los valores que son la copia de un objeto a otro son los tipos de referencia, a continuación, cualquier modificación de los valores en el objeto original se afectan los valores en el objeto copiado (ya que son sólo referencias al mismo objeto)

    Si usted necesita para clonar un objeto que tiene propiedades que son tipos de referencia que necesita para hacer esos tipos de clonable o hacer una copia manual de ellas por crear nuevas instancias como sea necesario.

    Conside utilizando el IClonable interfaz aunque no es la mejor de las soluciones en mi humilde opinión.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea