2010-11-11 22 views

Respuesta

13

Debe implementar la interfaz IClonable y proporcionar implementación para el método de clonación. No implemente esto si quiere evitar el lanzamiento.

Un método simple de clonación profunda podría ser serializar el objeto en la memoria y luego deserializarlo. Todos los tipos de datos personalizados utilizados en su clase deben ser serializables mediante el atributo [Serializable]. Para el clon se puede usar algo como

public MyClass Clone() 
    { 
     MemoryStream ms = new MemoryStream(); 
     BinaryFormatter bf = new BinaryFormatter(); 

     bf.Serialize(ms, this); 

     ms.Position = 0; 
     object obj = bf.Deserialize(ms); 
     ms.Close(); 

     return obj as MyClass; 
    } 

Si su clase sólo tiene value types, a continuación, se puede utilizar un copy constructor o simplemente asignar los valores a un nuevo objeto en el método Clone.

+0

Wow esa es una forma compleja de hacerlo, ¿por qué no usar simplemente un constructor de copia? –

+0

@Rowland no funcionará en tipos de referencia. editó mi respuesta de todos modos – Midhat

+1

@Rowland - un constructor de copias probablemente no copie las cosas, y necesita mantenimiento a medida que se agregan los campos. La serialización binaria es una forma muy común de hacer copias en profundidad. –

2

Comprobar este objeto clonación Usando IL en C# http://whizzodev.blogspot.com/2008/03/object-cloning-using-il-in-c.html

+0

También hace copias superficiales, si necesita una copia profunda tendrá que editar el generador de IL para navegar recursivamente a través del gráfico. –

+0

hay una versión más nueva disponible: http://whizzodev.blogspot.com/2008/06/object-deep-cloning-using-il-in-c_20.html –

3

¿Tiene que usar la interfaz ICloneable o es suficiente si sólo tienen dos métodos llamados Clone y Copy que se define en una interfaz genérica?

public class YourClass : ICloneable<YourClass> 
{ 
    // Constructor logic should be here 
    public YourClass Copy() { return this; }   
    public YourClass Clone() { return new YourClass(ID, Name, Dept); } 
} 

interface IClonable<T> 
{ 
    T Copy(); 
    T Clone(); 
} 

¿O he entendido mal algo?

Lo que estoy tratando de decir es que no tienes que hacerlo más complejo de lo que es? Si necesita que sus objetos se ajusten a alguna clase de usted, puede escribirlo usted mismo si el que se especifica en el marco .Net es complejo para la situación. También debe definir la diferencia con Clone y Copy, es decir, ¿qué significan para usted? Sé que hay varios sitios que especifican que Clone es una copia profunda y Copy es una copia superficial.

+2

El único problema es la sobrecarga de mantenimiento. Si agrega un nuevo campo, necesita actualizar su método 'CopyClone()' para incorporarlo (así como también el constructor al que llama). Si va a llamar a un constructor, en lugar de pasar campos discretos, debe pasar el objeto completo, es decir: 'return new YourClass (this)' –

+0

@Michael, eso es por supuesto cierto. Pero el punto es no hacerlo más complicado de lo que es hasta que realmente lo necesite. Y el método Copiar probablemente sea incorrecto (lo cambiará :)). Probablemente puedas cambiar la interfaz IClonable que tengo a una clase abstracta que contiene un método Clone que usa la reflexión o el patrón de serialización que Midhat ha escrito a continuación. –

+0

incluso iam confundido acerca de la documentación de diff. ¿sitio?. –

3

Quiere decir, cómo implementar ICloneable.Clone() y hacer que devuelva el tipo de la clase.

public class MyType : ICloneable 
{ 
    public MyType Clone() //called directly on MyType, returns MyType 
    { 
    return new MyType(/* class-dependant stuff goes here */); 
    } 
    object ICloneable.Clone() // called through ICloneable interface, returns object 
    { 
    return Clone(); 
    } 
} 
2

A menudo veo constructores de copia sugirieron como alternativa a un método de clonación, pero con la excepción de clases cerradas los comportamientos son muy diferentes. Si tengo un tipo Car, que simplemente admite propiedades VIN, BodyColor y BodyStyle, y un tipo derivado FancyCar, que también es compatible con InteriorFabric y SoundSystem, entonces el código que acepta un objeto de tipo Car y usa el constructor copia de coche para duplicarlo terminará arriba con un auto Si se pasa un FancyCar a dicho código, el "duplicado" resultante será un nuevo automóvil, que tiene un VIN, BodyColor y BodyStyle que coincide con el automóvil original, pero que no tendrá InteriorFabric o SoundSystem. Por el contrario, el código debía aceptar un automóvil y usar un método de clonación en él, pasar un FancyCar al código provocaría la producción de un FancyCar.

A menos que uno desee usar Reflection, cualquier método de clonación debe incluir en su base una llamada a base.MemberwiseClone. Como MemberwiseClone no es un método virtual, sugeriría definir un método de clonación virtual protegido; Es posible que también desee evitar que las clases secundarias llamen a MemberwiseClone definiendo una clase anidada de ámbito protegido con el mismo nombre (por lo tanto, si una clase descendiente intenta llamar a base.MemberwiseClone, no se interpretaría como una referencia sin sentido a la clase ficticia).

2

Aquí un ejemplo:

namespace XXX 
{ 
    [Serializable] 
    public class ItemChecklist : ICloneable 
    { 

     // [...here properties, attributes, etc....] 



     object ICloneable.Clone() 
     { 
      return this.Clone(); 
     } 
     public ItemChecklist Clone() 
     { 
      return (ItemChecklist)this.MemberwiseClone(); 
     } 


    } 
} 

es decir Si utiliza esta función, tendrá en "ItemAdd" una copia entera del objeto "itemTemp" con todos sus valores.

ItemChecklist itemAdd = itemTemp.Clone(); 
Cuestiones relacionadas