2011-12-28 8 views
9

MSDN da este ejemplo de una copia profunda (http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx)copia profunda en C#

public class Person 
{ 
    public int Age; 
    public string Name; 
    public IdInfo IdInfo; 

    public Person ShallowCopy() 
    { 
     return (Person)this.MemberwiseClone(); 
    } 

    public Person DeepCopy() 
    { 
     Person other = (Person) this.MemberwiseClone(); 
     other.IdInfo = new IdInfo(this.IdInfo.IdNumber); 
     return other; 
    } 
} 

Pero, ¿no es un nuevo objeto persona tiene que ser una instancia, y luego regresó? Por ejemplo, ¿este código es aceptable/igual/inferior al código anterior para realizar una copia profunda?

Según entiendo el método MemberwiseClone(), solo realiza una copia superficial, es decir, copia los valores/referencias del objeto copiado a un nuevo objeto. Esto da como resultado una copia superficial ya que las referencias de memoria son iguales, es decir, las referencias apuntan a los mismos objetos.

public class Person 
{ 
    public int Age; 
    public string Name; 
    public IdInfo IdInfo; 

    public Person ShallowCopy() 
    { 
     return (Person)this.MemberwiseClone(); 
    } 

    public Person DeepCopy() 
    { 
     Person other = new Person(); // difference 
     other.IdInfo = new IdInfo(this.IdInfo.IdNumber); 
     return other; 
    } 
} 
+0

posible duplicado de [Cómo implementar clonar, copiar método dentro de una clase?] (http://stackoverflow.com/questions/4152733/how-to-implement-clone-and-copy-method-inside-a-class) – Midhat

Respuesta

12

En el ejemplo que ha especificado, los valores de Edad y Nombre serían cero/en blanco.

Esto se debe al hecho de que crea una instancia del objeto Person, pero nunca establece los valores de estos campos.

De Object.MemberwiseClone Method

El método MemberwiseClone crea una copia superficial mediante la creación de un nuevo objeto y, a continuación, copiar los campos no estáticos del objeto actual a el nuevo objeto. Si un campo es un tipo de valor, se realiza una copia bit por bit del campo . Si un campo es un tipo de referencia, la referencia es copiada pero el objeto referido no; por lo tanto, el objeto original y su clon se refieren al mismo objeto.

Como puede ver, utilizando el método MemberwiseClone, sus campos de edad/nombre también se copiarán/clonarán.

5

El MemberwiseClone() crea una nueva instancia de la clase que se está copiando y también copia los campos escalares en los miembros correspondientes de la copia. Proporciona un mejor punto de partida para la copia profunda que simplemente un new, porque necesita "arreglar" solo los elementos que requieren una copia profunda.

0

Su nuevo método no copia el valor de esto.Edad y this.Name, así que creo que ni siquiera se llama copiar.

4

MemberwiseClone crea un nuevo objeto y copia todos los campos no estáticos. En el caso de los tipos de referencia, esto significa copiar las referencias. Entonces, sí, después de que un miembro clona sabiamente, los campos del nuevo objeto apuntan a los mismos objetos que los campos del objeto original (para los tipos de referencia). Es por eso que el ejemplo en MSDN crea una nueva instancia del IdInfo: para crear una copia de ese objeto también.

Su implementación DeepCopy está rota porque no copia todos los campos, pero si así fuera, el resultado no sería diferente de la solución MemberwiseClone.

Esta pregunta también podría ser una lectura interesante para usted: Create a Deep Copy in C#

3

La implementación de MemberwiseClone haría lo siguiente para su código.

Person p = new Person(); 
p.Age = this.Age; // value copy 
p.Name = this.Name; // value copy 
p.IdInfo = this.IdInfo; // reference copy. this object is the same in both coppies. 
return p; 
0

Su DeepCopy no copiará los campos de Edad y Nombre del objeto que se está copiando.Obtendrán sus valores predeterminados (T) en su lugar (Edad = 0, Nombre = nulo).

MemberwiseClone no crear un nuevo objeto igual que lo hizo, sino que también copia los campos:

Person other = new Person();

other.Age = this.Age;

other.Name = this.Name;

Como int es un tipo de valor que será copiado al nuevo objeto. El campo Nombre hará referencia a la misma cadena a la que se hizo referencia por Nombre; si no está bien, entonces necesitaría Clonar() y establecer la referencia en su método DeepCopy() como IdInfo.

De acuerdo con MSDN: El método MemberwiseClone crea una copia superficial creando un nuevo objeto y luego copiando los campos no estáticos del objeto actual en el nuevo objeto.

6

Como alternativa, si puede establecer el atributo Serializable en todas las clases implicadas, puede usar la serialización. A los efectos de una copia profunda genérica tengo este método object extensión:

public static class ObjectExtensions 
{ 
    #region Methods 

    public static T Copy<T>(this T source) 
    { 
     var isNotSerializable = !typeof(T).IsSerializable; 
     if (isNotSerializable) 
      throw new ArgumentException("The type must be serializable.", "source"); 

     var sourceIsNull = ReferenceEquals(source, null); 
     if (sourceIsNull) 
      return default(T); 

     var formatter = new BinaryFormatter(); 
     using (var stream = new MemoryStream()) 
     { 
      formatter.Serialize(stream, source); 
      stream.Seek(0, SeekOrigin.Begin); 
      return (T)formatter.Deserialize(stream); 
     } 
    } 

    #endregion 
} 

Esto también debería copiar su campo IdInfo.

uso es simple:

var copy = obj.Copy(); 
0

Otra alternativa como la extensión objeto es la siguiente:

public static class ObjectExtension 
{ 
     public static T Copy<T>(this T lObjSource) 
     { 
      T lObjCopy = (T)Activator.CreateInstance(typeof(T)); 

      foreach (PropertyInfo lObjCopyProperty in lObjCopy.GetType().GetProperties()) 
      { 
       lObjCopyProperty.SetValue 
       (
        lObjCopy, 
        lObjSource.GetType().GetProperties().Where(x => x.Name == lObjCopyProperty.Name).FirstOrDefault().GetValue(lObjSource) 
       ); 
      } 

      return lObjCopy; 
     } 
} 

Para su uso:

User lObjUserCopy = lObjUser.Copy(); 
Cuestiones relacionadas