2010-09-14 12 views

Antwort

32

Nun, nicht viel wirklich. Es verdient eine besondere Erwähnung in der Framework Design Guidelines als eine Schnittstelle zu vermeiden.

Implementieren Sie nicht ICloneable. There sind zwei allgemeine Möglichkeiten, ICloneable, entweder als eine tiefe oder nicht-tiefe Kopie zu implementieren. Die Tiefkopie kopiert das geklonte Objekt und alle Objekte , auf die das Objekt verweist, rekursiv , bis alle Objekte im Diagramm kopiert sind. Eine nicht-tiefe Kopie (bezogen auf als 'seicht', wenn nur die obersten Referenzen kopiert werden) kann keinen oder Teil einer tiefen Kopie machen. Da der Schnittstellenvertrag nicht den Typ des ausgeführten Klons angibt, haben unterschiedliche Klassen unterschiedliche Implementierungen. Ein Konsument kann nicht verlassen auf ICloneable, um sie wissen, ob ein Objekt tief geklont ist oder nicht.

Es gab in der Vergangenheit Diskussionen darüber, es zu veralten. Ich bin nicht sicher, was jemals daraus kam, aber die Framework-Designer haben zugegeben, dass es wahrscheinlich ein Fehler war.

Wenn Sie das Klonen unterstützen möchten, dann würde ich separate Schnittstellen IDeepCopy und IShallowCopy oder dergleichen erstellen und implementieren.

+3

+1, richtige Antwort. –

4

Kopie des angegebenen Objekts erstellen.

ICloneable Interface:

Unterstützt Klonen, die mit dem gleichen Wert wie eine bestehende Instanz eine neue Instanz einer Klasse erstellt.

EDIT: Scott Chamberlain absolut richtig. Diese Schnittstelle spezifiziert weder, dass diese Kopie tief oder flach sein soll. Und das ist eines der verwirrendsten Dinge an dieser Schnittstelle.

+0

Gerade falls Sie nicht wissen, was eine tiefe Kopie ist http://en.wikipedia.org/wiki/Object_copy#Deep_copy –

+0

„Clone kann entweder als tiefe Kopie oder eine flache Kopie implementiert werden. In einer tiefen Kopie werden alle Objekte dupliziert, während in einer flachen Kopie nur die Objekte der obersten Ebene dupliziert werden und die unteren Ebenen Verweise enthalten. " - MSDN-Dokumente für ICloneable.Clone. Also, nimm nicht an, dass es eine tiefe Kopie ist. – Powerlord

+0

@R. Bemrose: Ja, hast du recht. Ich habe meine Antwort bereits bearbeitet. –

5

Von MSDN: "Die ICloneable-Schnittstelle enthält ein Element, Clone, das das Klonen über das von MemberwiseClone hinausgehende unterstützen soll."

Es ist eine Schnittstelle, die bei Implementierung signalisiert, dass Instanzen der Klasse geklont und nicht nur flach kopiert werden. Die Implementierung der IClonable-Schnittstelle sagt jedoch nichts darüber aus, ob sie flach kopiert oder tief kopiert wird.

Es gibt eine interessante Diskussion über die Verwendung von IClonable hier: http://channel9.msdn.com/forums/TechOff/202972-IClonable-deep-vs-shallow-best-practise/.

1

Ich denke, ich habe eine gute Verwendung für iCloneable herausgefunden: um die Erstellung von Klassenhierarchien zu erleichtern, die sowohl klonierbare als auch nicht klonierbare Typen umfassen.

Wenn eine Klasse eine öffentliche Clone-Methode hat, ist es unmöglich, daraus eine Klasse abzuleiten, die nicht sinnvoll geklont werden kann, ohne gegen das Liskov-Substitutionsprinzip zu verstoßen. Das Problem ist, dass es für jede gegebene Klasse nützlich sein kann, sowohl eine Version, die geklont werden kann, als auch eine Version zu haben, die nicht-klonbare abgeleitete Klassen erlaubt.iCloneable bietet eine Möglichkeit, dies zu tun.

Angenommen, Sie möchten die Klassenhierarchie Widget, SuperWidget und SuperDuperWidget und SuperDuperNoncloneableWidget definieren. Widget, SuperWidget und SuperDuperWidget können jeweils das Klonen über die geschützte Methode unterstützen. Man kann von ihnen Klassen CloneableWidget, CloneableSuperWidget und CloneableSuperDuperWidget ableiten.

Wenn man nicht iCloneable (oder etwas Äquivalentes) verwendet, wäre es sehr schwierig, eine Funktion zu schreiben, die auf einem CloneableWidget funktioniert, aber auch auf einem CloneableSuperWidget funktionieren könnte. Bei Verwendung von iCloneable kann man jedoch die Funktion eines Widgets akzeptieren lassen, und es muss auch iCloneable sein. Dies ermöglicht es somit, in der gewünschten Hierarchie gut zu arbeiten.

Beachten Sie, dass iCloneable im Gegensatz zu anderen Schnittstellen nicht isoliert sinnvoll ist. Es ist nur als Typbeschränkung nützlich, wenn es auf eine Klasse angewendet wird, die das Klonen möglicherweise öffentlich unterstützt oder nicht; die seichte/tiefe Semantik wird diejenige dieser Klasse sein.

0

Was ist mit der Definition von IShallowClone und IDeepClone?

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; } 
}