2671 Stimmen

Tiefes Klonen von Objekten

Ich möchte etwas tun wie:

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = myObj.Clone();

Und nehmen Sie dann Änderungen am neuen Objekt vor, die sich nicht im ursprünglichen Objekt widerspiegeln.

Ich brauche diese Funktionalität nicht oft, und wenn es nötig war, habe ich ein neues Objekt erstellt und dann jede Eigenschaft einzeln kopiert, aber das hinterlässt bei mir immer das Gefühl, dass es eine bessere oder elegantere Möglichkeit gibt, die Situation zu lösen.

Wie kann ich ein Objekt klonen oder tief kopieren, so dass das geklonte Objekt geändert werden kann, ohne dass sich die Änderungen auf das Originalobjekt auswirken?

112 Stimmen

Kann nützlich sein: "Warum ist das Kopieren eines Objekts eine schreckliche Sache?" agiledeveloper.com/articles/cloning072002.htm

2 Stimmen

stackoverflow.com/questions/8025890/ Eine andere Lösung...

28 Stimmen

Werfen Sie einen Blick auf AutoMapper

30voto

alelom Punkte 1356

DeepCloner: Schnelles, einfaches und effektives NuGet-Paket für das Klonen

Nachdem ich alle Antworten gelesen habe, war ich überrascht, dass niemand dieses hervorragende Paket erwähnt hat:

DeepCloner GitHub-Projekt

DeepCloner NuGet-Paket

In der README finden Sie die Gründe, warum wir uns bei der Arbeit für dieses Programm entschieden haben:

  • Sie kann tief oder flach kopieren
  • Beim Deep Cloning bleibt der gesamte Objektgraph erhalten.
  • Verwendet Code-Generierung zur Laufzeit, daher ist das Klonen rasend schnell
  • Objekte werden von der internen Struktur kopiert, keine Methoden oder Koren aufgerufen
  • Sie müssen Klassen nicht in irgendeiner Weise kennzeichnen (z. B. Serializable-Attribut, oder Schnittstellen implementieren).
  • Es ist nicht erforderlich, den Objekttyp für das Klonen anzugeben. Das Objekt kann in eine Schnittstelle oder ein abstraktes Objekt umgewandelt werden (z. B. kann ein Array von Ints als abstraktes Array oder IEnumerable geklont werden; sogar null kann ohne Fehler geklont werden)
  • Geklontes Objekt hat keine Möglichkeit festzustellen, dass es ein Klon ist (außer mit sehr spezifischen Methoden)

Uso:

var deepClone = new { Id = 1, Name = "222" }.DeepClone();
var shallowClone = new { Id = 1, Name = "222" }.ShallowClone();

Leistung:

Das README enthält einen Leistungsvergleich verschiedener Klonbibliotheken und -methoden: DeepCloner Leistung .

Anforderungen:

  • .NET 4.0 oder höher oder .NET Standard 1.3 (.NET Core)
  • Erfordert die Berechtigung Full Trust oder die Berechtigung Reflection (MemberAccess)

3 Stimmen

Diese Frage ist ziemlich alt. Ich denke, diese Antwort sollte nach oben gehen, damit die Leute den Wert hier sehen können.

0 Stimmen

Eine zusätzliche Paketreferenz für das Klonen eines Objekts? Nicht so schön.

2 Stimmen

Fühlen Sie sich frei, eine der Millionen Lösungen, die in diesem Thread vorgeschlagen wurden, umzusetzen. Ich halte dieses Paket für eine sehr praktische Lösung. Ich wünschte nur, MS würde eine entsprechende Lösung in C# oder .NET einbetten.

27voto

Zach Burlingame Punkte 13286

Die kurze Antwort ist, Sie erben von der ICloneable-Schnittstelle und implementieren dann die Funktion .clone. Clone sollte eine mitgliederweise Kopie und eine tiefe Kopie auf jedes Mitglied, das es erfordert, durchführen und dann das resultierende Objekt zurückgeben. Dies ist eine rekursive Operation (sie erfordert, dass alle Mitglieder der Klasse, die Sie klonen wollen, entweder Werttypen sind oder ICloneable implementieren und dass deren Mitglieder entweder Werttypen sind oder ICloneable implementieren usw.).

Eine ausführlichere Erklärung zum Klonen mit ICloneable finden Sie unter dieser Artikel .

El lang Die Antwort lautet "es kommt darauf an". Wie bereits von anderen erwähnt, wird ICloneable nicht von Generics unterstützt, erfordert besondere Überlegungen für zirkuläre Klassenreferenzen und wird von einigen tatsächlich als eine "Fehler" im .NET Framework. Die Serialisierungsmethode hängt davon ab, dass Ihre Objekte serialisierbar sind, was sie möglicherweise nicht sind und worauf Sie keinen Einfluss haben. In der Community gibt es immer noch viele Diskussionen darüber, welches die "beste" Methode ist. In Wirklichkeit ist keine der Lösungen eine Einheitslösung für alle Situationen, wie ICloneable ursprünglich gedacht war.

Siehe das hier Artikel in der Entwicklerecke für ein paar weitere Optionen (Dank an Ian).

1 Stimmen

ICloneable hat keine generische Schnittstelle, so dass es nicht empfohlen wird, diese Schnittstelle zu verwenden.

0 Stimmen

Ihre Lösung funktioniert, bis es zirkuläre Verweise behandeln muss, dann beginnen die Dinge zu komplizieren, es ist besser zu versuchen, tiefes Klonen mit tiefen Serialisierung zu implementieren.

0 Stimmen

Leider sind auch nicht alle Objekte serialisierbar, so dass man auch diese Methode nicht immer verwenden kann. Der Link von Ian ist die bisher umfassendste Antwort.

26voto

dimarzionist Punkte 18137
  1. Grundsätzlich müssen Sie die ICloneable-Schnittstelle implementieren und dann das Kopieren von Objektstrukturen realisieren.
  2. Wenn es sich um eine tiefe Kopie aller Mitglieder handelt, müssen Sie sicherstellen (unabhängig von der von Ihnen gewählten Lösung), dass auch alle Kinder klonbar sind.
  3. Manchmal müssen Sie während dieses Prozesses einige Einschränkungen beachten, z.B. wenn Sie ORM-Objekte kopieren, erlauben die meisten Frameworks nur ein Objekt, das an die Sitzung angehängt ist, und Sie dürfen KEINE Klone dieses Objekts erstellen, oder wenn es möglich ist, müssen Sie sich um die Sitzungsanbindung dieser Objekte kümmern.

Zum Wohl.

4 Stimmen

ICloneable hat keine generische Schnittstelle, so dass es nicht empfohlen wird, diese Schnittstelle zu verwenden.

0 Stimmen

Einfache und prägnante Antworten sind die besten.

21voto

Michael Sander Punkte 2637

EDIT: Projekt ist eingestellt

Wenn Sie wirklich auf unbekannte Typen klonen wollen, können Sie einen Blick auf fastclone .

Das ist ausdrucksbasiertes Klonen, das etwa 10 Mal schneller als binäre Serialisierung funktioniert und die vollständige Integrität des Objektgraphen beibehält.

Das bedeutet: Wenn Sie mehrfach auf dasselbe Objekt in Ihrer Hierarchie verweisen, wird auch der Klon nur eine einzige Instanz haben, auf die verwiesen wird.

Es sind keine Schnittstellen, Attribute oder sonstige Änderungen an den zu klonenden Objekten erforderlich.

0 Stimmen

Diese scheint recht nützlich zu sein

0 Stimmen

Es ist einfacher, von einem Code-Snapshot auszugehen als von einem Gesamtsystem, insbesondere einem geschlossenen. Es ist durchaus verständlich, dass keine Bibliothek alle Probleme mit einem Schlag lösen kann. Einige Lockerungen sollten vorgenommen werden.

1 Stimmen

Ich habe Ihre Lösung ausprobiert, und sie scheint gut zu funktionieren, danke! Ich denke, diese Antwort sollte öfters hochgevotet werden. Die manuelle Implementierung von ICloneable ist mühsam und fehleranfällig, die Verwendung von Reflection oder Serialisierung ist langsam, wenn die Leistung wichtig ist und Sie Tausende von Objekten in einem kurzen Zeitraum kopieren müssen.

17voto

Stacked Punkte 6174

Halten Sie die Dinge einfach und verwenden Sie AutoMapper wie bereits von anderen erwähnt, ist es eine einfache kleine Bibliothek, um ein Objekt auf ein anderes abzubilden... Um ein Objekt in ein anderes mit demselben Typ zu kopieren, brauchen Sie nur drei Zeilen Code:

MyType source = new MyType();
Mapper.CreateMap<MyType, MyType>();
MyType target = Mapper.Map<MyType, MyType>(source);

Das Zielobjekt ist nun eine Kopie des Quellobjekts. Nicht einfach genug? Erstellen Sie eine Erweiterungsmethode, die Sie überall in Ihrer Lösung verwenden können:

public static T Copy<T>(this T source)
{
    T copy = default(T);
    Mapper.CreateMap<T, T>();
    copy = Mapper.Map<T, T>(source);
    return copy;
}

Die Erweiterungsmethode kann wie folgt verwendet werden:

MyType copy = source.Copy();

0 Stimmen

Seien Sie vorsichtig mit diesem Gerät, es funktioniert wirklich schlecht. Ich endete Wechsel zu johnc Antwort, die so kurz wie diese ist und führt eine Menge besser.

5 Stimmen

Damit wird nur eine oberflächliche Kopie erstellt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X