Ich habe eine generische Liste von Objekten in C # und möchte die Liste klonen. Die Elemente in der Liste sind klonbar, aber es scheint keine Option zu geben list.Clone().
@orip Ist nicht clone()per Definition eine tiefe Kopie? In C # kann man mit = leicht Zeiger weitergeben, dachte ich.
Chris
13
@ Chris eine flache Kopie kopiert eine Ebene tiefer als die Zeigerkopie. Beispielsweise enthält eine flache Kopie einer Liste dieselben Elemente, ist jedoch eine andere Liste.
Ich denke, List.ConvertAll könnte dies in kürzerer Zeit tun, da es das gesamte Array für die Liste vorab zuweisen kann, anstatt ständig die Größe ändern zu müssen.
MichaelGG
2
@MichaelGG, was ist, wenn Sie die Elemente in der Liste nicht konvertieren, sondern nur klonen / duplizieren möchten? Würde das funktionieren? || var clonedList = ListOfStrings.ConvertAll (p => p);
IbrarMumtaz
29
@IbrarMumtaz: Das ist dasselbe wie var clonedList = new List <string> (ListOfStrings);
Brandon Arnold
4
Schöne Lösung! Übrigens bevorzuge ich öffentliche statische List <T> CLone <T> ... In solchen Fällen ist es nützlicher, da keine weitere Umwandlung erforderlich ist: List <MyType> cloned = listToClone.Clone ();
Plutoz
2
Dies ist tiefes Klonen
George Birbilis
512
Wenn Ihre Elemente Werttypen sind, können Sie einfach Folgendes tun:
Wenn es sich jedoch um Referenztypen handelt und Sie eine tiefe Kopie wünschen (vorausgesetzt, Ihre Elemente werden ordnungsgemäß implementiert ICloneable), können Sie Folgendes tun:
Persönlich würde ich es vermeiden, ICloneableweil eine tiefe Kopie aller Mitglieder garantiert werden muss. Stattdessen würde ich vorschlagen, dass der Kopierkonstruktor oder eine solche Factory-Methode YourType.CopyFrom(YourType itemToCopy)eine neue Instanz von zurückgibt YourType.
Jede dieser Optionen kann durch eine Methode (Erweiterung oder auf andere Weise) umbrochen werden.
Ich denke, List <T> .ConvertAll sieht vielleicht besser aus, als eine neue Liste zu erstellen und foreach + add durchzuführen.
MichaelGG
2
@ Dimitri: Nein, das stimmt nicht. Das Problem ist, dass ICloneablein der Definition nie angegeben wurde, ob der Klon tief oder flach war, sodass Sie nicht bestimmen können, welche Art von Klonoperation ausgeführt wird, wenn ein Objekt ihn implementiert. Dies bedeutet, dass Sie, wenn Sie einen tiefen Klon von erstellen möchten, dies List<T>tun müssen, ohne ICloneablesicher zu sein, dass es sich um eine tiefe Kopie handelt.
Jeff Yates
5
Warum nicht die AddRange-Methode verwenden? ( newList.AddRange(oldList.Select(i => i.Clone())oder newList.AddRange(oldList.Select(i => new YourType(i))
Phoog
5
@phoog: Ich denke, dass es beim Scannen des Codes etwas weniger lesbar / verständlich ist, das ist alles. Lesbarkeit gewinnt für mich.
Jeff Yates
1
@JeffYates: Eine unzureichend berücksichtigte Falte ist, dass Dinge im Allgemeinen nur kopiert werden müssen, wenn ein Ausführungspfad vorhanden ist, der sie mutieren würde. Es ist sehr üblich, dass unveränderliche Typen einen Verweis auf eine Instanz eines veränderlichen Typs enthalten, diese Instanz jedoch niemals etwas aussetzen, das sie mutiert. Das unnötige Kopieren von Dingen, die sich nie ändern werden, kann manchmal zu einem erheblichen Leistungsverlust führen und die Speichernutzung um Größenordnungen erhöhen.
Supercat
84
Für eine flache Kopie können Sie stattdessen die GetRange-Methode der generischen List-Klasse verwenden.
Sie können dies auch erreichen, indem Sie mit dem Konstruktor der Liste <T> eine Liste <T> angeben, aus der kopiert werden soll. zB var flatClonedList = neue Liste <MyObject> (originalList);
Arkiliknam
9
Ich benutze oft List<int> newList = oldList.ToList(). Gleicher Effekt. Die Lösung von Arkiliknam ist meiner Meinung nach jedoch am besten für die Lesbarkeit geeignet.
Dan Bechard
82
publicstaticobjectDeepClone(object obj){object objResult =null;
using (MemoryStream ms =newMemoryStream()){BinaryFormatter bf =newBinaryFormatter();
bf.Serialize(ms, obj);
ms.Position=0;
objResult = bf.Deserialize(ms);}return objResult;}
Dies ist eine Möglichkeit, dies mit C # und .NET 2.0 zu tun. Ihr Objekt muss sein [Serializable()]. Ziel ist es, alle Referenzen zu verlieren und neue zu erstellen.
+1 - Ich mag diese Antwort - sie ist schnell, schmutzig, böse und sehr effektiv. Ich habe in Silverlight verwendet und den DataContractSerializer verwendet, da der BinarySerializer nicht verfügbar war. Wer muss Seiten mit Objektkloncode schreiben, wenn Sie dies einfach tun können? :)
Slugster
3
Ich mag das. Während es schön ist, Dinge "richtig" zu machen, ist schnell und schmutzig oft nützlich.
Odrade
3
Schnell! aber: Warum dreckig?
Raiserle
2
Dieser tiefe Klon ist schnell und einfach. Seien Sie vorsichtig mit anderen Vorschlägen auf dieser Seite. Ich habe mehrere ausprobiert und sie klonen nicht tief.
RandallTo
2
Der einzige negative Aspekt, wenn Sie es so nennen können, ist, dass Ihre Klassen als serialisierbar markiert sein müssen, damit dies funktioniert.
Tuukka Haapaniemi
29
Um eine Liste zu klonen, rufen Sie einfach .ToList () auf. Dadurch wird eine flache Kopie erstellt.
Microsoft(R)Roslyn C# Compiler version 2.3.2.62116Loading context from'CSharpInteractive.rsp'.Type"#help"for more information.>var x =newList<int>(){3,4};>var y = x.ToList();> x.Add(5)> x
List<int>(3){3,4,5}> y
List<int>(2){3,4}>
Eine kleine Warnung, dies ist eine flache Kopie ... Dadurch werden zwei Listenobjekte erstellt, aber die darin enthaltenen Objekte sind dieselben. Das Ändern einer Eigenschaft ändert dasselbe Objekt / dieselbe Eigenschaft in der ursprünglichen Liste.
Mark G
22
Nach einer geringfügigen Änderung können Sie auch klonen:
publicstatic T DeepClone<T>(T obj){
T objResult;
using (MemoryStream ms =newMemoryStream()){BinaryFormatter bf =newBinaryFormatter();
bf.Serialize(ms, obj);
ms.Position=0;
objResult =(T)bf.Deserialize(ms);}return objResult;}
Vergessen Sie nicht, dass das T serialisierbar sein sollte, sonst erhalten Sie die System.Runtime.Serialization.SerializationException.
Bence Végert
Gute Antwort. Ein Hinweis: Sie können if (!obj.GetType().IsSerializable) return default(T);als erste Anweisung hinzufügen , die die Ausnahme verhindert. Und wenn Sie es in eine Erweiterungsmethode ändern, können Sie sogar den Elvis-Operator wie var b = a?.DeepClone();( var a = new List<string>() { "a", "b" }; zum Beispiel angegeben) verwenden.
Matt
15
Wenn Sie List<T>keinen tatsächlichen Klon für jedes einzelne Objekt in Ihrem Objekt benötigen, können Sie eine Liste am besten klonen, indem Sie eine neue Liste mit der alten Liste als Auflistungsparameter erstellen.
Ich stimme user49126 zu. Ich sehe, dass es sich um eine flache Kopie handelt und Änderungen an einer Liste in der anderen Liste wiedergegeben werden.
Seidleroni
1
@Seidleroni, du liegst falsch. Die an den Listenelementen vorgenommenen Änderungen wirken sich auf die andere Liste aus, Änderungen an der Liste selbst jedoch nicht.
Wellington Zanelli
Dies ist eine flache Kopie.
Elliot Chen
Wie ist das eine flache Kopie?
mko
2
@WellingtonZanelli Gerade bestätigt, dass durch das Entfernen eines Elements aus myList auch dieses aus cloneOfMyList entfernt wird.
Nick Gallimore
13
Die Verwendung von AutoMapper (oder einer von Ihnen bevorzugten Zuordnungsbibliothek) zum Klonen ist einfach und sehr wartbar.
Möglicherweise nicht der effizienteste Weg, dies zu tun, aber wenn Sie es nicht 100 oder 1000 Mal tun, werden Sie möglicherweise nicht einmal den Geschwindigkeitsunterschied bemerken.
Es geht nicht um den Geschwindigkeitsunterschied, es geht um die Lesbarkeit. Wenn ich zu dieser Codezeile käme, würde ich mir den Kopf schlagen und mich fragen, warum sie eine Drittanbieter-Bibliothek eingeführt haben, um ein Objekt zu serialisieren und dann zu deserialisieren, von dem ich keine Ahnung hätte, warum es passiert. Dies würde auch für eine Modellliste mit Objekten mit kreisförmiger Struktur nicht funktionieren.
Jonathon Cwik
1
Dieser Code hat für mich beim Deep Cloning hervorragend funktioniert. Die App migriert das Dokument-Boilerplate von Dev zu QA zu Prod. Jedes Objekt ist ein Paket aus mehreren Dokumentvorlagenobjekten, und jedes Dokument besteht wiederum aus einer Liste von Absatzobjekten. Mit diesem Code kann ich die .NET "Quell" -Objekte serialisieren und sofort in neue "Ziel" -Objekte deserialisieren, die dann in einer anderen Umgebung in einer SQL-Datenbank gespeichert werden. Nach tonnenweise Recherchen fand ich viele Dinge, von denen viele zu umständlich waren, und beschloss, dies zu versuchen. Dieser kurze und flexible Ansatz war "genau richtig"!
Mein Freund Gregor Martinovic und ich haben diese einfache Lösung mit einem JavaScript Serializer entwickelt. Es ist nicht erforderlich, Klassen als serialisierbar zu kennzeichnen und in unseren Tests mit dem Newtonsoft JsonSerializer noch schneller als mit BinaryFormatter. Mit Erweiterungsmethoden, die für jedes Objekt verwendet werden können.
Standardoption für .NET JavascriptSerializer:
publicstatic T DeepCopy<T>(this T value){JavaScriptSerializer js =newJavaScriptSerializer();string json = js.Serialize(value);return js.Deserialize<T>(json);}
Ich habe Glück, wenn jemand dies jemals liest ... aber um keine Liste von Typobjekten in meinen Klonmethoden zurückzugeben, habe ich eine Schnittstelle erstellt:
publicinterfaceIMyCloneable<T>{
T Clone();}
Dann habe ich die Erweiterung angegeben:
publicstaticList<T>Clone<T>(thisList<T> listToClone)where T :IMyCloneable<T>{return listToClone.Select(item =>(T)item.Clone()).ToList();}
Und hier ist eine Implementierung der Schnittstelle in meiner A / V-Markierungssoftware. Ich wollte, dass meine Clone () -Methode eine Liste von VidMark zurückgibt (während die ICloneable-Schnittstelle wollte, dass meine Methode eine Liste von Objekten zurückgibt):
Und schließlich die Verwendung der Erweiterung innerhalb einer Klasse:
privateList<VidMark>_VidMarks;privateList<VidMark>_UndoVidMarks;//Other methods instantiate and fill the listsprivatevoidSetUndoVidMarks(){_UndoVidMarks=_VidMarks.Clone();}
Sie können die Liste auch einfach mit in ein Array konvertieren ToArrayund das Array dann mit klonen Array.Clone(...). Abhängig von Ihren Anforderungen können die in der Array-Klasse enthaltenen Methoden Ihren Anforderungen entsprechen.
Das funktioniert nicht; Änderungen an den Werten im geklonten Array STILL ändern die Werte in der ursprünglichen Liste.
Bernoulli Lizard
Sie können var clonedList = ListOfStrings.ConvertAll (p => p) verwenden. wie von @IbrarMumtaz gegeben .... Funktioniert effektiv ... Änderungen an einer Liste werden für sich behalten und nicht in einer anderen reflektiert
zainul
2
Sie können die Erweiterungsmethode verwenden:
namespace extension
{publicclass ext
{publicstaticList<double> clone(thisList<double> t){List<double> kop =newList<double>();int x;for(x =0; x < t.Count; x++){
kop.Add(t[x]);}return kop;}};}
Sie können alle Objekte klonen, indem Sie beispielsweise ihre Werttypelemente verwenden. Betrachten Sie diese Klasse:
publicclass matrix
{publicList<List<double>> mat;publicint rows,cols;public matrix clone(){// create new object
matrix copy =new matrix();// firstly I can directly copy rows and cols because they are value types
copy.rows =this.rows;
copy.cols =this.cols;// but now I can no t directly copy mat because it is not value type soint x;// I assume I have clone method for List<double>for(x=0;x<this.mat.count;x++){
copy.mat.Add(this.mat[x].clone());}// then mat is clonedreturn copy;// and copy of original is returned }};
Hinweis: Wenn Sie beim Kopieren (oder Klonen) Änderungen vornehmen, wirkt sich dies nicht auf das ursprüngliche Objekt aus.
Anscheinend überspringen einige Sammlungen (z. B. DataGrids SelectedItems bei Silverlight) die Implementierung von CopyTo, was bei diesem Ansatz ein Problem darstellt
George Birbilis,
1
Ich benutze Automapper, um ein Objekt zu kopieren. Ich habe gerade eine Zuordnung eingerichtet, die ein Objekt auf sich selbst abbildet. Sie können diesen Vorgang beliebig umbrechen.
Für eine tiefe Kopie ist ICloneable die richtige Lösung, aber hier ist ein ähnlicher Ansatz wie bei ICloneable, bei dem der Konstruktor anstelle der ICloneable-Schnittstelle verwendet wird.
publicclassStudent{publicStudent(Student student){FirstName= student.FirstName;LastName= student.LastName;}publicstringFirstName{get;set;}publicstringLastName{get;set;}}// wherever you have the listList<Student> students;// and then where you want to make a copyList<Student> copy = students.Select(s =>newStudent(s)).ToList();
Sie benötigen die folgende Bibliothek, in der Sie die Kopie erstellen
using System.Linq
Sie können auch eine for-Schleife anstelle von System.Linq verwenden, aber Linq macht sie präzise und sauber. Ebenso könnten Sie tun, was andere Antworten vorgeschlagen haben, und Erweiterungsmethoden usw. erstellen, aber nichts davon ist notwendig.
Das nennt man einen "Kopierkonstruktor". Es ist ein fehleranfälliger Ansatz. Wenn Sie Student ein neues Feld hinzufügen, müssen Sie daran denken, es dem Kopierkonstruktor hinzuzufügen. Die Hauptidee hinter "Klon" ist es, dieses Problem zu vermeiden.
Kenno
2
Selbst mit ICloneable müssen Sie eine "Clone" -Methode für Ihre Klasse haben. Sofern Sie keine Reflektion verwenden (die Sie auch im obigen Ansatz verwenden könnten), wird diese Clone-Methode dem obigen Copy-Konstruktor-Ansatz sehr ähnlich sein und unter dem gleichen Problem leiden, dass für neue / geänderte Felder aktualisiert werden muss. Aber das heißt "Die Klasse muss aktualisiert werden, wenn sich Felder der Klasse ändern". Natürlich tut es das;)
ztorstri
0
Der folgende Code sollte mit minimalen Änderungen in eine Liste übertragen werden.
Grundsätzlich funktioniert es, indem mit jeder aufeinanderfolgenden Schleife eine neue Zufallszahl aus einem größeren Bereich eingefügt wird. Wenn es bereits Zahlen gibt, die gleich oder höher sind, verschieben Sie diese Zufallszahlen um eins nach oben, damit sie in den neuen größeren Bereich von Zufallsindizes übertragen werden.
// Example Usageint[] indexes = getRandomUniqueIndexArray(selectFrom.Length, toSet.Length);for(int i =0; i < toSet.Length; i++)
toSet[i]= selectFrom[indexes[i]];privateint[] getRandomUniqueIndexArray(int length,int count){if(count > length || count <1|| length <1)returnnewint[0];int[] toReturn =newint[count];if(count == length){for(int i =0; i < toReturn.Length; i++) toReturn[i]= i;return toReturn;}Random r =newRandom();int startPos = count -1;for(int i = startPos; i >=0; i--){int index = r.Next(length - i);for(int j = startPos; j > i; j--)if(toReturn[j]>= index)
toReturn[j]++;
toReturn[i]= index;}return toReturn;}
Eine andere Sache: Sie könnten Reflexion gebrauchen. Wenn Sie dies richtig zwischenspeichern, werden 1.000.000 Objekte in 5,6 Sekunden geklont (leider 16,4 Sekunden bei inneren Objekten).
[ProtoContract(ImplicitFields=ImplicitFields.AllPublic)]publicclassPerson{...JobJobDescription...}[ProtoContract(ImplicitFields=ImplicitFields.AllPublic)]publicclassJob{...}privatestaticreadonlyType stringType =typeof(string);publicstaticclassCopyFactory{staticreadonlyDictionary<Type,PropertyInfo[]>ProperyList=newDictionary<Type,PropertyInfo[]>();privatestaticreadonlyMethodInfoCreateCopyReflectionMethod;staticCopyFactory(){CreateCopyReflectionMethod=typeof(CopyFactory).GetMethod("CreateCopyReflection",BindingFlags.Static|BindingFlags.Public);}publicstatic T CreateCopyReflection<T>(T source)where T :new(){var copyInstance =new T();var sourceType =typeof(T);PropertyInfo[] propList;if(ProperyList.ContainsKey(sourceType))
propList =ProperyList[sourceType];else{
propList = sourceType.GetProperties(BindingFlags.Public|BindingFlags.Instance);ProperyList.Add(sourceType, propList);}foreach(var prop in propList){varvalue= prop.GetValue(source,null);
prop.SetValue(copyInstance,value!=null&& prop.PropertyType.IsClass&& prop.PropertyType!= stringType ?CreateCopyReflectionMethod.MakeGenericMethod(prop.PropertyType).Invoke(null,newobject[]{value}):value,null);}return copyInstance;}
Ich habe es auf einfache Weise mit der Watcher-Klasse gemessen.
var person =newPerson{...};for(var i =0; i <1000000; i++){
personList.Add(person);}var watcher =newStopwatch();
watcher.Start();var copylist = personList.Select(CopyFactory.CreateCopyReflection).ToList();
watcher.Stop();var elapsed = watcher.Elapsed;
ERGEBNIS: Mit dem inneren Objekt PersonInstance - 16.4 ist PersonInstance = null - 5.6
CopyFactory ist nur meine Testklasse, in der ich Dutzende von Tests einschließlich der Verwendung von Ausdruck habe. Sie können dies in einer anderen Form in einer Erweiterung oder was auch immer implementieren. Vergessen Sie nicht das Caching.
Ich habe die Serialisierung noch nicht getestet, bezweifle aber eine Verbesserung mit einer Million Klassen. Ich werde etwas schnelles Protobuf / Newton versuchen.
PS: Der Einfachheit halber habe ich hier nur Auto-Property verwendet. Ich könnte mit FieldInfo aktualisieren, oder Sie sollten dies einfach selbst implementieren.
Ich habe kürzlich den Serializer für Protokollpuffer mit der sofort einsatzbereiten DeepClone-Funktion getestet . Es gewinnt mit 4,2 Sekunden auf einer Million einfacher Objekte, aber wenn es um innere Objekte geht, gewinnt es mit dem Ergebnis 7,4 Sekunden.
Serializer.DeepClone(personList);
ZUSAMMENFASSUNG: Wenn Sie keinen Zugriff auf die Klassen haben, hilft dies. Ansonsten kommt es auf die Anzahl der Objekte an. Ich denke, Sie könnten Reflexion von bis zu 10.000 Objekten verwenden (vielleicht etwas weniger), aber für mehr als dies wird der Serializer für Protokollpuffer eine bessere Leistung erzielen.
Es gibt eine einfache Möglichkeit, Objekte in C # mit einem JSON-Serializer und -Deserializer zu klonen.
Sie können eine Erweiterungsklasse erstellen:
using Newtonsoft.Json;staticclass typeExtensions
{[Extension()]publicstatic T jsonCloneObject<T>(T source){string json =JsonConvert.SerializeObject(source);returnJsonConvert.DeserializeObject<T>(json);}}
clone()
per Definition eine tiefe Kopie? In C # kann man mit = leicht Zeiger weitergeben, dachte ich.Antworten:
Sie können eine Erweiterungsmethode verwenden.
quelle
Wenn Ihre Elemente Werttypen sind, können Sie einfach Folgendes tun:
Wenn es sich jedoch um Referenztypen handelt und Sie eine tiefe Kopie wünschen (vorausgesetzt, Ihre Elemente werden ordnungsgemäß implementiert
ICloneable
), können Sie Folgendes tun:Ersetzen Sie natürlich
ICloneable
die oben genannten Generika und setzen Sie sie mit dem Elementtyp um, der implementiert wirdICloneable
.Wenn Ihr Elementtyp nicht unterstützt
ICloneable
, aber über einen Kopierkonstruktor verfügt, können Sie stattdessen Folgendes tun:Persönlich würde ich es vermeiden,
ICloneable
weil eine tiefe Kopie aller Mitglieder garantiert werden muss. Stattdessen würde ich vorschlagen, dass der Kopierkonstruktor oder eine solche Factory-MethodeYourType.CopyFrom(YourType itemToCopy)
eine neue Instanz von zurückgibtYourType
.Jede dieser Optionen kann durch eine Methode (Erweiterung oder auf andere Weise) umbrochen werden.
quelle
ICloneable
in der Definition nie angegeben wurde, ob der Klon tief oder flach war, sodass Sie nicht bestimmen können, welche Art von Klonoperation ausgeführt wird, wenn ein Objekt ihn implementiert. Dies bedeutet, dass Sie, wenn Sie einen tiefen Klon von erstellen möchten, diesList<T>
tun müssen, ohneICloneable
sicher zu sein, dass es sich um eine tiefe Kopie handelt.newList.AddRange(oldList.Select(i => i.Clone())
odernewList.AddRange(oldList.Select(i => new YourType(i)
)Für eine flache Kopie können Sie stattdessen die GetRange-Methode der generischen List-Klasse verwenden.
Zitiert aus: Generika-Rezepte
quelle
List<int> newList = oldList.ToList()
. Gleicher Effekt. Die Lösung von Arkiliknam ist meiner Meinung nach jedoch am besten für die Lesbarkeit geeignet.Dies ist eine Möglichkeit, dies mit C # und .NET 2.0 zu tun. Ihr Objekt muss sein
[Serializable()]
. Ziel ist es, alle Referenzen zu verlieren und neue zu erstellen.quelle
Um eine Liste zu klonen, rufen Sie einfach .ToList () auf. Dadurch wird eine flache Kopie erstellt.
quelle
Nach einer geringfügigen Änderung können Sie auch klonen:
quelle
if (!obj.GetType().IsSerializable) return default(T);
als erste Anweisung hinzufügen , die die Ausnahme verhindert. Und wenn Sie es in eine Erweiterungsmethode ändern, können Sie sogar den Elvis-Operator wievar b = a?.DeepClone();
(var a = new List<string>() { "a", "b" };
zum Beispiel angegeben) verwenden.Wenn Sie
List<T>
keinen tatsächlichen Klon für jedes einzelne Objekt in Ihrem Objekt benötigen, können Sie eine Liste am besten klonen, indem Sie eine neue Liste mit der alten Liste als Auflistungsparameter erstellen.Änderungen
myList
wie Einfügen oder Entfernen wirken sich nicht auscloneOfMyList
und umgekehrt.Die tatsächlichen Objekte, die die beiden Listen enthalten, sind jedoch immer noch dieselben.
quelle
Die Verwendung von AutoMapper (oder einer von Ihnen bevorzugten Zuordnungsbibliothek) zum Klonen ist einfach und sehr wartbar.
Definieren Sie Ihr Mapping:
Mach die Magie:
quelle
Wenn Sie sich nur für Werttypen interessieren ...
Und Sie kennen den Typ:
Wenn Sie den Typ vorher nicht kennen, benötigen Sie eine Hilfsfunktion:
Das Gerechte:
quelle
Wenn Sie in Ihrem Projekt bereits auf Newtonsoft.Json verwiesen haben und Ihre Objekte serialisierbar sind, können Sie immer Folgendes verwenden:
Möglicherweise nicht der effizienteste Weg, dies zu tun, aber wenn Sie es nicht 100 oder 1000 Mal tun, werden Sie möglicherweise nicht einmal den Geschwindigkeitsunterschied bemerken.
quelle
quelle
quelle
quelle
Mein Freund Gregor Martinovic und ich haben diese einfache Lösung mit einem JavaScript Serializer entwickelt. Es ist nicht erforderlich, Klassen als serialisierbar zu kennzeichnen und in unseren Tests mit dem Newtonsoft JsonSerializer noch schneller als mit BinaryFormatter. Mit Erweiterungsmethoden, die für jedes Objekt verwendet werden können.
Standardoption für .NET JavascriptSerializer:
Schnellere Option mit Newtonsoft JSON :
quelle
quelle
Ich habe Glück, wenn jemand dies jemals liest ... aber um keine Liste von Typobjekten in meinen Klonmethoden zurückzugeben, habe ich eine Schnittstelle erstellt:
Dann habe ich die Erweiterung angegeben:
Und hier ist eine Implementierung der Schnittstelle in meiner A / V-Markierungssoftware. Ich wollte, dass meine Clone () -Methode eine Liste von VidMark zurückgibt (während die ICloneable-Schnittstelle wollte, dass meine Methode eine Liste von Objekten zurückgibt):
Und schließlich die Verwendung der Erweiterung innerhalb einer Klasse:
Gefällt es jemandem? Irgendwelche Verbesserungen?
quelle
Sie können die Liste auch einfach mit in ein Array konvertieren
ToArray
und das Array dann mit klonenArray.Clone(...)
. Abhängig von Ihren Anforderungen können die in der Array-Klasse enthaltenen Methoden Ihren Anforderungen entsprechen.quelle
Sie können die Erweiterungsmethode verwenden:
Sie können alle Objekte klonen, indem Sie beispielsweise ihre Werttypelemente verwenden. Betrachten Sie diese Klasse:
Hinweis: Wenn Sie beim Kopieren (oder Klonen) Änderungen vornehmen, wirkt sich dies nicht auf das ursprüngliche Objekt aus.
quelle
Wenn Sie eine geklonte Liste mit derselben Kapazität benötigen, können Sie Folgendes versuchen:
quelle
Ich habe selbst eine Erweiterung erstellt, die die ICollection von Elementen konvertiert, die IClonable nicht implementieren
quelle
Ich benutze Automapper, um ein Objekt zu kopieren. Ich habe gerade eine Zuordnung eingerichtet, die ein Objekt auf sich selbst abbildet. Sie können diesen Vorgang beliebig umbrechen.
http://automapper.codeplex.com/
quelle
Die Verwendung einer Besetzung kann in diesem Fall für eine flache Kopie hilfreich sein:
angewendet auf generische Liste:
quelle
Für eine tiefe Kopie ist ICloneable die richtige Lösung, aber hier ist ein ähnlicher Ansatz wie bei ICloneable, bei dem der Konstruktor anstelle der ICloneable-Schnittstelle verwendet wird.
Sie benötigen die folgende Bibliothek, in der Sie die Kopie erstellen
Sie können auch eine for-Schleife anstelle von System.Linq verwenden, aber Linq macht sie präzise und sauber. Ebenso könnten Sie tun, was andere Antworten vorgeschlagen haben, und Erweiterungsmethoden usw. erstellen, aber nichts davon ist notwendig.
quelle
Der folgende Code sollte mit minimalen Änderungen in eine Liste übertragen werden.
Grundsätzlich funktioniert es, indem mit jeder aufeinanderfolgenden Schleife eine neue Zufallszahl aus einem größeren Bereich eingefügt wird. Wenn es bereits Zahlen gibt, die gleich oder höher sind, verschieben Sie diese Zufallszahlen um eins nach oben, damit sie in den neuen größeren Bereich von Zufallsindizes übertragen werden.
quelle
Eine andere Sache: Sie könnten Reflexion gebrauchen. Wenn Sie dies richtig zwischenspeichern, werden 1.000.000 Objekte in 5,6 Sekunden geklont (leider 16,4 Sekunden bei inneren Objekten).
Ich habe es auf einfache Weise mit der Watcher-Klasse gemessen.
ERGEBNIS: Mit dem inneren Objekt PersonInstance - 16.4 ist PersonInstance = null - 5.6
CopyFactory ist nur meine Testklasse, in der ich Dutzende von Tests einschließlich der Verwendung von Ausdruck habe. Sie können dies in einer anderen Form in einer Erweiterung oder was auch immer implementieren. Vergessen Sie nicht das Caching.
Ich habe die Serialisierung noch nicht getestet, bezweifle aber eine Verbesserung mit einer Million Klassen. Ich werde etwas schnelles Protobuf / Newton versuchen.
PS: Der Einfachheit halber habe ich hier nur Auto-Property verwendet. Ich könnte mit FieldInfo aktualisieren, oder Sie sollten dies einfach selbst implementieren.
Ich habe kürzlich den Serializer für Protokollpuffer mit der sofort einsatzbereiten DeepClone-Funktion getestet . Es gewinnt mit 4,2 Sekunden auf einer Million einfacher Objekte, aber wenn es um innere Objekte geht, gewinnt es mit dem Ergebnis 7,4 Sekunden.
ZUSAMMENFASSUNG: Wenn Sie keinen Zugriff auf die Klassen haben, hilft dies. Ansonsten kommt es auf die Anzahl der Objekte an. Ich denke, Sie könnten Reflexion von bis zu 10.000 Objekten verwenden (vielleicht etwas weniger), aber für mehr als dies wird der Serializer für Protokollpuffer eine bessere Leistung erzielen.
quelle
Es gibt eine einfache Möglichkeit, Objekte in C # mit einem JSON-Serializer und -Deserializer zu klonen.
Sie können eine Erweiterungsklasse erstellen:
Klonen und Einwenden:
quelle