Was ist das Problem mit IClonable?
-
Hallo,
ich habe momentan ein Verständnisproblem mit
IClonable
. Eigentlich ist das Interface und wozu es da ist ja ziemlich simpel. Trotzdem scheint es ja geradezu "verpönt" zu sein dieses zu benutzen, zumindest wird auf diversen websites (unter anderem von Microsoft selbst) davon abgeraten, dieses zu benutzen.Als Argumente werden immer wieder angebracht dass es für den Benutzer nicht ersichtlich ist ob eine "deep" copy oder eine "shallow" copy gemacht wird.
Soweit so gut, nur jetzt meine Frage: In wiefern ist das anders zu einem Benutzerdefinierten Copy-Konstruktor in C++?
Dort ist ja auch nicht ersichtlich ob ein Copy-Konstruktor jetzt eine deep- oder shallow copy erstellt (je nachdem was der Benutzer halt will). Der Beliebtheit von Copy-Konstruktoren scheint das aber keinen Abbruch zu tun. Zumindest hab ich im Rahmen von C++ noch nie von diesem Problem gelesen.
Also, warum ist das in C# wichtig/relevant? Warum kann man nicht einfach davon ausgehen dass der Entwickler einer Klasse X eine geeignete
Clone
Funktion implementiert haben wird? Und warum sollte man überhaupt etwas wieClone
verwenden und nicht einfach den Copy-Konstruktor?
-
Ich bin noch nie drübergestolpert, dass ICloneable verpönt wäre. Habs aber tatsächlich kaum mal benutzt, gefallen hats mir auch noch nie.
Ich könnte mir vorstellen, dass die Semantik den Unterschied ausmacht. In .NET hast du nur Referenzen, die du rumreichst. Da macht es einen Unterschied, ob du wirklich eine Kopie gemacht hast, oder immer noch eine Referenz auf dieselben Daten rumreichst, die verändert werden könnte. Gibt ja nicht mal ein const für Parameter. In C++ gibts hingegen die Unterscheidung zwischen Zeigern/Referenzen und Value Objekten und außerdem gibts const.
Ist aber mehr oder weniger ein Schuss ins blaue. In C++ muss man sich halt die Doku anschauen und wissen, was man tut. Wenn ich mit einer neuen Bibliothek arbeite, muss ich mich natürlich auch zuerst einarbeiten, damit ich weiß, was Wrapper Objekte sind, und wo die Daten wirklich kopiert werden.
-
Ich denke auch, daß das seltene Auftreten von
Clone()
-Methoden daran liegt, daß C# Referenzsemantik begünstigt und man die Art Probleme, die zur Einführung von Move-Semantik und R-Value-Referenzen in C++ geführt haben, überhaupt nicht hat. Außerdem ist es gebräuchlich, möglichst viele Dinge mit unveränderlichen Datentypen abzubilden, und da erübrigt sich das Klonen eh.An den Stellen, wo man
Clone()
dann wirklich braucht (z.B. beiSqlCommandBuilder
), kommt mir das oft wie ein Designfehler vor. Ich kann mir schon sinnvolle Verwendungen vorstellen (z.B., wenn ich meine Objekthierarchie mit einer Snapshot-Fähigkeit ausstatten will), aber vielen bin ich auch noch nicht begegnet.
-
Mechanics schrieb:
Ich bin noch nie drübergestolpert, dass ICloneable verpönt wäre.
Ja, wird eben von MS und auf diversen Stackoverflow Seiten immer wieder diskutiert. Vielleicht nicht direkt verpönt, aber zumindest kontrovers
Mechanics schrieb:
In C++ muss man sich halt die Doku anschauen und wissen, was man tut.
Sollte man in C# ja auch, oder? Zumindest hab ich mir in C# auch schon oft ins Bein geschossen weil mir nicht genau klar war was Methode x jetzt exakt macht
audacia schrieb:
Ich denke auch, daß das seltene Auftreten von
Clone()
-Methoden daran liegt, daß C# Referenzsemantik begünstigt und man die Art Probleme, die zur Einführung von Move-Semantik und R-Value-Referenzen in C++ geführt haben, überhaupt nicht hat. Außerdem ist es gebräuchlich, möglichst viele Dinge mit unveränderlichen Datentypen abzubilden, und da erübrigt sich das Klonen eh.An den Stellen, wo man
Clone()
dann wirklich braucht (z.B. beiSqlCommandBuilder
), kommt mir das oft wie ein Designfehler vor. Ich kann mir schon sinnvolle Verwendungen vorstellen (z.B., wenn ich meine Objekthierarchie mit einer Snapshot-Fähigkeit ausstatten will), aber vielen bin ich auch noch nicht begegnet.Naja, ich will schon öfter mal zum Beispiel eine List<T> per Value (also deep) kopieren. Etwa weil ein Algorithmus diese umsortieren muss, die Original Liste aber in der ursprünglichen Form erhalten bleiben soll.
Da wär ein Clone schon sehr praktisch. Momentan hab ich halt eine DeepClone Extension Methode, aber besser fände ich es wenn List<T> einfach ein entprechendes Interface implementieren würde und so "von Haus aus" schon kopierbar wäre.
-
happystudent schrieb:
Naja, ich will schon öfter mal zum Beispiel eine List<T> per Value (also deep) kopieren. Etwa weil ein Algorithmus diese umsortieren muss, die Original Liste aber in der ursprünglichen Form erhalten bleiben soll.
Da wär ein Clone schon sehr praktisch. Momentan hab ich halt eine DeepClone Extension Methode, aber besser fände ich es wenn List<T> einfach ein entprechendes Interface implementieren würde und so "von Haus aus" schon kopierbar wäre.
Was macht diese Methode anders als der Konstruktor
List(IEnumerable<T>)
?
-
Wer Lust hat, kann sich auch mal den myCSharp-Thread Kopie ohne ICloneable [oder warum man Objekte nicht kopieren sollte; Transaktionen auf Objekten] durchlesen.
-
TyRoXx schrieb:
Was macht diese Methode anders als der Konstruktor
List(IEnumerable<T>)
?Oh, den kannte ich ja noch gar nicht
Gut, dann ist das für List<T> wohl hinfällig ...Wobei das ja dann quasi ein Copy-Konstruktor ist und da ist ja wieder nicht ersichtlich ob jetzt eine Deep oder Shallow Copy gemacht wird. Darüber scheint sich aber keiner zu beschweren, was mMn etwas widersprüchlich ist ... Zumindest ist da vom Prinzip her ja nicht wirklich ein Unterschied.
Th69 schrieb:
Wer Lust hat, kann sich auch mal den myCSharp-Thread Kopie ohne ICloneable [oder warum man Objekte nicht kopieren sollte; Transaktionen auf Objekten] durchlesen.
Hm, ich versteh jetzt den Identitätsbegriff nicht so ganz den die da verwenden und ist auch ganz schön umständlich (es geht ja nur um ne simple Kopie eines Objekts)? Also ich weiß nicht ob ich das so gut finden soll ...
-
Die Identität ist ... naja die Identität halt
In C++ könnte man die Adresse des Objekts hernehmen.
In C# geht es um die selbe Sache, nur dass die Adresse im Speicher sich dort ändern kann, weil die Objekte ja vom GC rumgeschoben werden.
-
happystudent schrieb:
Wobei das ja dann quasi ein Copy-Konstruktor ist und da ist ja wieder nicht ersichtlich ob jetzt eine Deep oder Shallow Copy gemacht wird.
Doch, ist es.
Eine "deep copy" erfordert entweder das Mitwirken der Objekte in der Liste oder den Einsatz von Reflection.
List<T>
hat keinICloneable
-Constraint fürT
, und Cloning per Reflection ist nicht immer richtig/eindeutig (wo hört die tiefe Kopie auf? Wie geht man mit OS-Handles um? etc.) und vor allem sehr ineffizient. Dementgegen kann man eine Liste vonT
s immer kopieren, ohne mehr überT
wissen zu müssen. Also, was tut der Konstruktor wohl?
-
@audacia
Es ist in vielen Fällen nicht ersichtlich. Gerade wenn man thirdparty Libraries verwendet.EDIT: OK, hier gings speziell um List<T>. Da kann man es sich natürlich herleiten. Ich meine nur: in vielen anderen Fällen kann man das halt nicht. /EDIT