Ich habe eine Sammlung von Objekten, und ich versuche, diese Sammlung zu klonen und zu versuchen, die Implikationen der verschiedenen Ansätze zu verstehen.
Das Objekt in der Sammlung hat ungefähr 20 Eigenschaften, alle Zeichenfolgen, Ints, Floats (diese Objekte haben keine darin eingebetteten Objekte). Die zwei Ansätze sind:
Create DeepClone () Methode:
%Vor%}
Schreiben Sie manuell "copy" code, wo ich die Sammlung durchsuche und ein neues Objekt "neu" einfüge und dann manuell alle 20 Eigenschaften einstelle. etwas wie das
%Vor%}
Ich erhalte sehr widersprüchliche Ergebnisse, daher wollte ich das Feedback der Leute bekommen:
Sollte einer viel schneller sein als der andere? Ich hätte die Wahl zwei geglaubt, aber meine Tests scheinen das nicht zu unterstützen, also versuche ich herauszufinden, ob ich etwas falsch mache.
Gibt es eine Möglichkeit, dies noch schneller zu machen?
Nun, zuerst muss die BinaryFormatter-Route definitiv langsamer sein, da sie die Reflektion verwendet, um Eigenschaften zu erhalten / zu setzen. Die gebräuchlichste Methode ist die Verwendung der IClonable-Schnittstelle in Verbindung mit einem Kopierkonstruktor.
%Vor%Natürlich braucht man eigentlich nur den Kopierkonstruktor, der die schnellste Methode sein sollte. Wenn Ihre Objekte einfach sind, sollten Sie versuchen, die eingebaute Funktion MemberwiseClone zu verwenden.
%Vor%Inzwischen habe ich einen Testcode geschrieben, um zu sehen, ob MemberwiseClone () erheblich schneller oder langsamer war als ein Kopierkonstruktor. Sie finden es hier . Ich habe festgestellt, dass MemberwiseClone tatsächlich viel langsamer ist als ein CopyConstructor, zumindest in kleinen Klassen. Beachten Sie, dass die Verwendung von BinaryFormatter wahnsinnig langsam ist.
In meiner vorherigen Rolle haben wir genau dieses Problem untersucht, als wir Objekte zwischenspeichern und sie klonen wollten, bevor wir sie aus dem Cache übergaben.
Wir haben ein detailliertes Benchmarking durchgeführt und festgestellt, dass die Einstellung der Eigenschaften immer mindestens eine Größenordnung schneller war als die Methode BinaryFormatter
, obwohl offensichtlich eine Hand-Roll-Implementierung im Gegensatz zu der viel einfacheren erforderlich BinaryFormatter
Ansatz. Für tiefe Objektdiagramme wurde der Unterschied deutlicher IIRC.
IImutable
, aber Sie könnten auch ein Attribut oder ein solches verwenden), würden wir "klonen", indem wir die ursprüngliche Instanz zurückgeben. Da wir wussten, dass niemand es mutieren konnte, war es sicher, die gleiche Instanz zurückzugeben. Offensichtlich war dies die schnellste Art von "Klon", obwohl eindeutig kein Klon überhaupt. IDeepCloneable<T>
Schnittstelle implementiert hat (was Ihrem zweiten Beispiel entspricht - aber generisch), würden wir das verwenden. [Diese generische Schnittstelle würde von einem nicht-generischen Äquivalent IDeepCloneable
] BinaryFormatter
. Ich erwähne den "unveränderlichen" Ansatz, denn je nachdem, was Sie tun, ist es manchmal der beste Weg, die Klassen neu zu gestalten, die Sie klonen müssen, damit sie überhaupt nicht geklont werden müssen. Wenn sie nach der Erstellung im Wesentlichen schreibgeschützt sind, ist das einfach. Aber selbst wenn nicht, ist manchmal der Ansatz vom Builder / unveränderlichen Typ nützlich (siehe Uri
vs. UriBuilder
im Framework. Ersteres ist im Wesentlichen unveränderbar, während letzteres zum Erstellen und / oder Mutieren von Instanzen des früher).
Die Verwendung der Serialisierung ist eine sehr clevere Idee. Das Einstellen der Eigenschaften sollte jedoch genauso schnell erfolgen, und die meiste Zeit (außer wenn die Objekte wirklich klein sind) müssen schneller sein - Sie arbeiten weniger und verwenden keine Reflektion.
Können Sie einen Fall reproduzieren, bei dem die Verwendung der Serialisierung schneller war als das Kopieren der Eigenschaften "von Hand"?
Serialisierung ist definitiv langsamer als nur die Zuweisung von Eigenschaften.
Binäre Serialisierung ist vorzuziehen, weil der Code einfach und leicht zu pflegen ist.
Die Eigenschaftenzuweisung ist stattdessen besser, weil während des Klons möglicherweise keine alle Eigenschaften des Objekts geklont werden sollen, sondern diese übrigens serialisiert werden sollen. Kurz gesagt, Sie haben mehr Kontrolle über den Fluss.
Alle Ansätze setzen 1) serialisierbare und 2) einfache (genug) Objekte voraus. Wenn Sie über Objekte verfügen, die Hashtabellen enthalten können, die Hashtabellen enthalten können, ohne Einschränkungen für die Tiefe, dann haben Sie ein Durcheinander in Ihren Händen, ohne dass ein rekursives Objekt durchsucht wird.
Tags und Links c# performance clone