2010-09-14 9 views

Respuesta

32

Bueno, no mucho en realidad. Obtuvo una mención especial en el Framework Design Guidelines como una interfaz para evitar.

No instale ICloneable. Existen dos formas generales de implementar ICloneable, ya sea como una copia profunda o no profunda. Copia profunda copia el objeto clonado y todos los objetos referenciados por el objeto, recursivamente hasta que todos los objetos en el gráfico sean copiados. Una copia no profunda (referida a como 'superficial' si solo se copian las referencias de nivel superior ) no puede hacer ninguna, o parte de una copia profunda. Dado que el contrato de interfaz no especifica el tipo de clonación realizada, las diferentes clases tienen implementaciones diferentes . Un consumidor no puede confiar en ICloneable para hacerles saber si un objeto está clonado a fondo o no .

Se ha debatido en el pasado sobre la obsolescencia. No estoy seguro de qué salió de eso, pero los diseñadores del marco han admitido que probablemente fue un error.

Si desea admitir la clonación, crearía e implementaría interfaces separadas IDeepCopy y IShallowCopy o similares.

+3

+1, respuesta correcta. –

4

Crear copia del objeto especificado.

ICloneable Interface:

Soporta la clonación, que crea un nuevo instancia de una clase con el mismo valor como una instancia existente.

EDIT: Scott Chamberlain absolutamente a la derecha. Esta interfaz no especifica tampoco esta copia debe ser profunda o superficial. Y esta es una de las cosas más confusas sobre esta interfaz.

+0

En caso de que no sabe lo que es una copia profunda http://en.wikipedia.org/wiki/Object_copy#Deep_copy –

+0

"Clon se puede implementar ya sea como una copia profunda o una copia superficial. En una copia profunda, todos los objetos están duplicados, mientras que, en una copia superficial, solo los objetos de nivel superior están duplicados y los niveles inferiores contienen referencias ". - Documentos de MSDN para ICloneable.Clone. Entonces, no asumas que es una copia profunda. – Powerlord

+0

@R. Bemrose: sí, tienes razón. Ya he editado mi respuesta. –

5

De MSDN: "La interfaz ICloneable contiene un miembro, Clone, que está destinado a admitir la clonación más allá de la proporcionada por MemberwiseClone."

Es una interfaz que si se implementa indica que las instancias de la clase se clonan y no solo se copian superficialmente. Sin embargo, la implementación de la interfaz IClonable no dice nada si se copia poco o si se copia profundamente.

Hay una discusión interesante sobre cómo usar IClonable aquí: http://channel9.msdn.com/forums/TechOff/202972-IClonable-deep-vs-shallow-best-practise/.

1

Creo que he encontrado un buen uso para iCloneable: para facilitar la creación de jerarquías de clases que incluyen tanto tipos clonables como no clonables.

Si una clase tiene un método de clonación público, entonces es imposible derivar de ella una clase que no pueda ser clonada significativamente, sin violar el Principio de sustitución de Liskov. El problema es que para cualquier clase dada puede ser útil tener una versión que sea clonable y una versión que permita clases derivadas no clonables.iCloneable proporciona una forma de hacer esto.

Supongamos que uno quiere definir la jerarquía de clases Widget, SuperWidget y SuperDuperWidget, y SuperDuperNoncloneableWidget. Widget, SuperWidget y SuperDuperWidget pueden admitir la clonación a través de un método protegido. Uno puede derivar de las clases CloneableWidget, CloneableSuperWidget y CloneableSuperDuperWidget.

Si uno no usara iCloneable (o algo equivalente), sería muy difícil escribir una función que funcionaría en un ClonableWidget, pero también podría funcionar en un CloneableSuperWidget. Sin embargo, utilizando iCloneable, uno puede tener la función de aceptar un widget, y también requiere que sea iCloneable. Esto permitirá que uno trabaje bien dentro de la jerarquía deseada.

Tenga en cuenta que, a diferencia de otras interfaces, iCloneable no es significativo de forma aislada. Solo es útil como restricción de tipo cuando se aplica a una clase que puede o no respaldar públicamente la clonación; la semántica superficial/profunda será la de esa clase.

0

¿Qué tal si se define IShallowClone y IDeepClone de esta manera?

public interface IShallowClone<T> { T ShallowClone(); } 
public interface IDeepClone<T> { T DeepClone(); } 

public interface IA : IShallowClone<IA>, IDeepClone<IA> { double a { get; } IA ia { get; } } 
public interface IB : IA, IShallowClone<IB>, IDeepClone<IB> { double b { get; } IB ib { get; } } 

public class A : IA 
{ 
    public double a { get; private set; } 
    public IA ia { get; private set; } 
    public A(IA that) { this.a = that.a; this.ia = (ia as IDeepClone<IA>).DeepClone(); } 
    public IA DeepClone() { return new A(this); } 
    public IA ShallowClone() { return this.MemberwiseClone() as IA; } 
} 
public class B : A, IB 
{ public double b { get; private set; } 
    public IB ib { get; private set; } 
    public B(IB that) : base(that) { this.b = that.b; this.ib = (ib as IDeepClone<IB>).DeepClone(); } 
    public new IB DeepClone() { return new B(this); } 
    public new IB ShallowClone() { return this.MemberwiseClone() as IB; } 
} 
Cuestiones relacionadas