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 wie Clone 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. bei SqlCommandBuilder ), 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. bei SqlCommandBuilder ), 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 kein ICloneable -Constraint für T , 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 von T s immer kopieren, ohne mehr über T 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


Log in to reply