J'ai une liste générique d'objets en C # et je souhaite cloner la liste. Les éléments de la liste sont clonables, mais il ne semble pas y avoir d'option à faire list.Clone().
@orip N'est-ce pas clone()par définition une copie complète ? En C #, vous pouvez facilement passer des pointeurs avec =, pensais-je.
Chris
13
@Chris une copie superficielle copie un niveau plus profond que la copie du pointeur. Par exemple, une copie superficielle d'une liste aura les mêmes éléments, mais sera une liste différente.
Je pense que List.ConvertAll pourrait le faire plus rapidement, car il peut pré-allouer le tableau entier pour la liste, au lieu d'avoir à redimensionner tout le temps.
MichaelGG
2
@MichaelGG, que se passe-t-il si vous ne voulez pas convertir, mais simplement cloner / dupliquer les éléments de la liste? Est-ce que cela fonctionnerait? || var clonedList = ListOfStrings.ConvertAll (p => p);
IbrarMumtaz
29
@IbrarMumtaz: C'est la même chose que var clonedList = new List <string> (ListOfStrings);
Brandon Arnold,
4
Bonne solution! Soit dit en passant, je préfère la liste statique publique <T> CLone <T> ... Elle est plus utile dans des cas comme celui-ci, car aucune conversion supplémentaire n'est nécessaire: List <MyType> cloned = listToClone.Clone ();
Plutoz
2
c'est du clonage profond
George Birbilis
513
Si vos éléments sont des types de valeur, vous pouvez simplement faire:
Cependant, s'il s'agit de types de référence et que vous souhaitez une copie complète (en supposant que vos éléments soient correctement implémentés ICloneable), vous pouvez faire quelque chose comme ceci:
Personnellement, j'éviterais en ICloneableraison de la nécessité de garantir une copie complète de tous les membres. Au lieu de cela, je suggère le constructeur de copie ou une méthode d'usine comme YourType.CopyFrom(YourType itemToCopy)celle-ci renvoie une nouvelle instance de YourType.
Chacune de ces options peut être encapsulée par une méthode (extension ou autre).
Je pense que List <T> .ConvertAll pourrait être plus agréable que de créer une nouvelle liste et de faire un foreach + add.
MichaelGG
2
@Dimitri: Non, ce n'est pas vrai. Le problème est que, lorsqu'elle a ICloneableété définie, la définition n'a jamais indiqué si le clone était profond ou peu profond, vous ne pouvez donc pas déterminer quel type d'opération de clonage sera effectué lorsqu'un objet l'implémentera. Cela signifie que si vous voulez faire un clone profond de List<T>, vous devrez le faire sans ICloneableêtre sûr qu'il s'agit d'une copie complète.
Jeff Yates
5
Pourquoi ne pas utiliser la méthode AddRange? ( newList.AddRange(oldList.Select(i => i.Clone())ou newList.AddRange(oldList.Select(i => new YourType(i))
phoog
5
@phoog: Je pense que c'est un peu moins lisible / compréhensible lors de la numérisation du code, c'est tout. La lisibilité gagne pour moi.
Jeff Yates
1
@JeffYates: Une ride insuffisamment prise en compte est que les choses n'ont généralement besoin d'être copiées que s'il existe un chemin d'exécution qui les muterait. Il est très courant que les types immuables contiennent une référence à une instance de type mutable, mais n'exposez jamais cette instance à rien qui la muterait. La copie inutile de choses qui ne changeront jamais peut parfois être une perte de performance majeure , augmentant l'utilisation de la mémoire par ordre de grandeur.
supercat
84
Pour une copie superficielle, vous pouvez utiliser à la place la méthode GetRange de la classe List générique.
Vous pouvez également y parvenir en utilisant le constructeur de la liste <T> pour spécifier une liste <T> à partir de laquelle copier. par exemple var shallowClonedList = new List <MyObject> (originalList);
Arkiliknam
9
J'utilise souvent List<int> newList = oldList.ToList(). Même effet. Cependant, la solution d'Arkiliknam est la meilleure pour la lisibilité à mon avis.
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;}
C'est une façon de le faire avec C # et .NET 2.0. Votre objet doit l'être [Serializable()]. Le but est de perdre toutes les références et d'en construire de nouvelles.
+1 - j'aime cette réponse - elle est rapide, sale, méchante et très efficace. J'ai utilisé Silverlight et utilisé le DataContractSerializer car le BinarySerializer n'était pas disponible. Qui a besoin d'écrire des pages de code de clonage d'objet alors que vous pouvez le faire? :)
slugster
3
J'aime ça. Bien qu'il soit agréable de faire les choses "correctement", rapide et sale est souvent utile.
Odrade
3
Rapide! mais: pourquoi sale?
raiserle
2
Ce clone profond et est rapide et facile. Attention aux autres suggestions sur cette page. J'en ai essayé plusieurs et ils ne clonent pas profondément.
RandallTo
2
Le seul aspect négatif, si vous pouvez l'appeler ainsi, est que vos classes doivent être marquées Sérialisable pour que cela fonctionne.
Tuukka Haapaniemi le
30
Pour cloner une liste, il suffit d'appeler .ToList (). Cela crée une copie superficielle.
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}>
Un petit avertissement c'est une copie superficielle ... Cela créera deux objets de liste, mais les objets à l'intérieur seront les mêmes. C'est-à-dire que changer une propriété changera le même objet / propriété dans la liste d'origine.
Mark G
22
Après une légère modification, vous pouvez également cloner:
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;}
N'oubliez pas que le T doit être sérialisable, sinon vous obtenez System.Runtime.Serialization.SerializationException.
Bence Végert
Bonne réponse. Un conseil: vous pouvez ajouter if (!obj.GetType().IsSerializable) return default(T);comme première instruction, ce qui empêche l'exception. Et si vous le changez en méthode d'extension, vous pouvez même utiliser l'opérateur Elvis comme var b = a?.DeepClone();(donné var a = new List<string>() { "a", "b" }; par exemple).
Matt
15
Sauf si vous avez besoin d'un clone réel de chaque objet à l'intérieur de votre List<T>, la meilleure façon de cloner une liste est de créer une nouvelle liste avec l'ancienne liste comme paramètre de collection.
Je suis d'accord avec l'utilisateur 49126, je constate qu'il s'agit d'une copie superficielle et les modifications apportées à une liste se reflètent dans l'autre liste.
Seidleroni
1
@Seidleroni, vous vous trompez. Les modifications apportées à la liste sont affectées sur l'autre liste, les modifications dans la liste elle-même ne le sont pas.
Wellington Zanelli
Ceci est une copie superficielle.
Elliot Chen
Comment est-ce une copie superficielle?
mko
2
@WellingtonZanelli vient de confirmer que la suppression d'un élément de myList le supprime également de cloneOfMyList.
Nick Gallimore
13
Utiliser AutoMapper (ou la bibliothèque de mappage que vous préférez) pour cloner est simple et très facile à gérer.
Ce n'est peut-être pas le moyen le plus efficace de le faire, mais à moins que vous ne le fassiez des centaines de milliers de fois, vous ne remarquerez peut-être même pas la différence de vitesse.
Il ne s'agit pas de la différence de vitesse, c'est de la lisibilité. Si je venais à cette ligne de code, je me giflerais la tête et me demanderais pourquoi ils ont introduit une bibliothèque tierce pour sérialiser puis désérialiser un objet dont je n'aurais aucune idée pourquoi cela se produit. De plus, cela ne fonctionnerait pas pour une liste de modèles avec des objets qui ont une structure circulaire.
Jonathon Cwik
1
Ce code a parfaitement fonctionné pour moi pour le clonage en profondeur. L'application migre le passe-partout de document de Dev à QA vers Prod. Chaque objet est un paquet de plusieurs objets de modèle de document, et chaque document à son tour est composé d'une liste d'objets de paragraphe. Ce code m'a permis de sérialiser les objets "source" .NET et de les désérialiser immédiatement en de nouveaux objets "cibles", qui sont ensuite enregistrés dans une base de données SQL dans un environnement différent. Après des tonnes de recherches, j'ai trouvé beaucoup de choses, dont beaucoup étaient trop lourdes, et j'ai décidé d'essayer. Cette approche courte et flexible était "juste ce qu'il fallait"!
Mon ami Gregor Martinovic et moi avons trouvé cette solution simple en utilisant un sérialiseur JavaScript. Il n'est pas nécessaire de marquer les classes comme sérialisables et dans nos tests en utilisant Newtonsoft JsonSerializer encore plus rapidement qu'en utilisant BinaryFormatter. Avec des méthodes d'extension utilisables sur chaque objet.
Option standard .NET JavascriptSerializer:
publicstatic T DeepCopy<T>(this T value){JavaScriptSerializer js =newJavaScriptSerializer();string json = js.Serialize(value);return js.Deserialize<T>(json);}
Je serai chanceux si quelqu'un lit jamais ceci ... mais afin de ne pas retourner une liste d'objets type dans mes méthodes Clone, j'ai créé une interface:
publicinterfaceIMyCloneable<T>{
T Clone();}
Ensuite, j'ai spécifié l'extension:
publicstaticList<T>Clone<T>(thisList<T> listToClone)where T :IMyCloneable<T>{return listToClone.Select(item =>(T)item.Clone()).ToList();}
Et voici une implémentation de l'interface dans mon logiciel de marquage A / V. Je voulais que ma méthode Clone () retourne une liste de VidMark (tandis que l'interface ICloneable voulait que ma méthode retourne une liste d'objets):
Et enfin, l'utilisation de l'extension à l'intérieur d'une classe:
privateList<VidMark>_VidMarks;privateList<VidMark>_UndoVidMarks;//Other methods instantiate and fill the listsprivatevoidSetUndoVidMarks(){_UndoVidMarks=_VidMarks.Clone();}
Vous pouvez également simplement convertir la liste en un tableau à l'aide ToArray, puis cloner le tableau à l'aide Array.Clone(...). Selon vos besoins, les méthodes incluses dans la classe Array peuvent répondre à vos besoins.
Cela ne fonctionne pas; les modifications apportées aux valeurs du tableau cloné TOUJOURS modifier les valeurs de la liste d'origine.
Bernoulli Lizard
vous pouvez utiliser var clonedList = ListOfStrings.ConvertAll (p => p); comme indiqué par @IbrarMumtaz .... Fonctionne efficacement ... Les modifications apportées à une liste sont conservées pour elles-mêmes et ne doivent pas se refléter dans une autre
zainul
2
Vous pouvez utiliser la méthode d'extension:
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;}};}
Vous pouvez cloner tous les objets en utilisant leurs membres de type valeur par exemple, considérez cette classe:
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 }};
Remarque: si vous effectuez des modifications sur la copie (ou le clonage), cela n'affectera pas l'objet d'origine.
semble que certaines collections (par exemple SelectedItems de DataGrid chez Silverlight) sautent l'implémentation de CopyTo qui est un problème avec cette approche
George Birbilis
1
J'utilise automapper pour copier un objet. Je viens de configurer un mappage qui mappe un objet sur lui-même. Vous pouvez terminer cette opération comme vous le souhaitez.
Pour une copie complète, ICloneable est la bonne solution, mais voici une approche similaire à ICloneable utilisant le constructeur au lieu de l'interface ICloneable.
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();
vous aurez besoin de la bibliothèque suivante où vous faites la copie
using System.Linq
vous pouvez également utiliser une boucle for au lieu de System.Linq, mais Linq la rend concise et propre. De même, vous pouvez faire comme d'autres réponses l'ont suggéré et créer des méthodes d'extension, etc., mais rien de tout cela n'est nécessaire.
C'est ce qu'on appelle un "constructeur de copie". C'est une approche sujette aux erreurs, chaque fois que vous ajoutez un nouveau champ à Student, vous devez vous rappeler de l'ajouter au constructeur de copie. L'idée principale derrière "clone" est d'éviter ce problème.
kenno
2
Même avec ICloneable, vous devez avoir une méthode "Clone" sur votre classe. À moins que vous n'utilisiez la réflexion (que vous pourriez également utiliser dans l'approche ci-dessus), cette méthode de clonage ressemblera beaucoup à l'approche du constructeur de copie ci-dessus et souffrira du même problème de mise à jour pour les champs nouveaux / modifiés. Mais cela veut dire "La classe doit être mise à jour lorsque les champs de la classe changent". Bien sûr que
oui
0
Le code suivant doit être transféré sur une liste avec un minimum de modifications.
Fondamentalement, cela fonctionne en insérant un nouveau nombre aléatoire à partir d'une plus grande plage avec chaque boucle successive. S'il existe déjà des nombres qui sont identiques ou supérieurs à lui, déplacez ces nombres aléatoires d'un pour qu'ils soient transférés dans la nouvelle gamme plus large d'index aléatoires.
// 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;}
Autre chose: vous pouvez utiliser la réflexion. Si vous le cachez correctement, il clonera 1 000 000 d'objets en 5,6 secondes (malheureusement, 16,4 secondes avec des objets internes).
[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;}
Je l'ai mesuré d'une manière simple, en utilisant la classe Watcher.
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;
CopyFactory est juste ma classe de test où j'ai une douzaine de tests, y compris l'utilisation de l'expression. Vous pouvez l'implémenter sous une autre forme dans une extension ou autre. N'oubliez pas la mise en cache.
Je n'ai pas encore testé la sérialisation, mais je doute d'une amélioration avec un million de classes. Je vais essayer quelque chose de rapide protobuf / newton.
PS: par souci de simplicité de lecture, je n'ai utilisé ici que la propriété automatique. Je pourrais mettre à jour avec FieldInfo, ou vous devriez facilement l'implémenter par vous-même.
J'ai récemment testé le sérialiseur Protocol Buffers avec la fonction DeepClone prête à l'emploi. Il gagne avec 4,2 secondes sur un million d'objets simples, mais en ce qui concerne les objets intérieurs, il gagne avec le résultat 7,4 secondes.
Serializer.DeepClone(personList);
RÉSUMÉ: Si vous n'avez pas accès aux cours, cela vous aidera. Sinon, cela dépend du nombre d'objets. Je pense que vous pouvez utiliser la réflexion jusqu'à 10 000 objets (peut-être un peu moins), mais pour plus que cela, le sérialiseur Protocol Buffers fonctionnera mieux.
Il existe un moyen simple de cloner des objets en C # à l'aide d'un sérialiseur et désérialiseur JSON.
Vous pouvez créer une classe d'extension:
using Newtonsoft.Json;staticclass typeExtensions
{[Extension()]publicstatic T jsonCloneObject<T>(T source){string json =JsonConvert.SerializeObject(source);returnJsonConvert.DeserializeObject<T>(json);}}
clone()
par définition une copie complète ? En C #, vous pouvez facilement passer des pointeurs avec =, pensais-je.Réponses:
Vous pouvez utiliser une méthode d'extension.
la source
Si vos éléments sont des types de valeur, vous pouvez simplement faire:
Cependant, s'il s'agit de types de référence et que vous souhaitez une copie complète (en supposant que vos éléments soient correctement implémentés
ICloneable
), vous pouvez faire quelque chose comme ceci:De toute évidence, remplacez
ICloneable
les génériques ci-dessus et effectuez un cast avec le type d'élément implémentéICloneable
.Si votre type d'élément ne prend pas en charge
ICloneable
mais a un constructeur de copie, vous pouvez le faire à la place:Personnellement, j'éviterais en
ICloneable
raison de la nécessité de garantir une copie complète de tous les membres. Au lieu de cela, je suggère le constructeur de copie ou une méthode d'usine commeYourType.CopyFrom(YourType itemToCopy)
celle-ci renvoie une nouvelle instance deYourType
.Chacune de ces options peut être encapsulée par une méthode (extension ou autre).
la source
ICloneable
été définie, la définition n'a jamais indiqué si le clone était profond ou peu profond, vous ne pouvez donc pas déterminer quel type d'opération de clonage sera effectué lorsqu'un objet l'implémentera. Cela signifie que si vous voulez faire un clone profond deList<T>
, vous devrez le faire sansICloneable
être sûr qu'il s'agit d'une copie complète.newList.AddRange(oldList.Select(i => i.Clone())
ounewList.AddRange(oldList.Select(i => new YourType(i)
)Pour une copie superficielle, vous pouvez utiliser à la place la méthode GetRange de la classe List générique.
Tiré de: Recettes génériques
la source
List<int> newList = oldList.ToList()
. Même effet. Cependant, la solution d'Arkiliknam est la meilleure pour la lisibilité à mon avis.C'est une façon de le faire avec C # et .NET 2.0. Votre objet doit l'être
[Serializable()]
. Le but est de perdre toutes les références et d'en construire de nouvelles.la source
Pour cloner une liste, il suffit d'appeler .ToList (). Cela crée une copie superficielle.
la source
Après une légère modification, vous pouvez également cloner:
la source
if (!obj.GetType().IsSerializable) return default(T);
comme première instruction, ce qui empêche l'exception. Et si vous le changez en méthode d'extension, vous pouvez même utiliser l'opérateur Elvis commevar b = a?.DeepClone();
(donnévar a = new List<string>() { "a", "b" };
par exemple).Sauf si vous avez besoin d'un clone réel de chaque objet à l'intérieur de votre
List<T>
, la meilleure façon de cloner une liste est de créer une nouvelle liste avec l'ancienne liste comme paramètre de collection.Des modifications
myList
telles que l'insertion ou la suppression n'affecteront pascloneOfMyList
et vice versa.Les objets réels que contiennent les deux listes sont cependant toujours les mêmes.
la source
Utiliser AutoMapper (ou la bibliothèque de mappage que vous préférez) pour cloner est simple et très facile à gérer.
Définissez votre cartographie:
Faites la magie:
la source
Si vous ne vous souciez que des types de valeur ...
Et vous connaissez le type:
Si vous ne connaissez pas le type auparavant, vous aurez besoin d'une fonction d'assistance:
Le juste:
la source
Si vous avez déjà référencé Newtonsoft.Json dans votre projet et que vos objets sont sérialisables, vous pouvez toujours utiliser:
Ce n'est peut-être pas le moyen le plus efficace de le faire, mais à moins que vous ne le fassiez des centaines de milliers de fois, vous ne remarquerez peut-être même pas la différence de vitesse.
la source
la source
la source
la source
Mon ami Gregor Martinovic et moi avons trouvé cette solution simple en utilisant un sérialiseur JavaScript. Il n'est pas nécessaire de marquer les classes comme sérialisables et dans nos tests en utilisant Newtonsoft JsonSerializer encore plus rapidement qu'en utilisant BinaryFormatter. Avec des méthodes d'extension utilisables sur chaque objet.
Option standard .NET JavascriptSerializer:
Option plus rapide avec Newtonsoft JSON :
la source
la source
Je serai chanceux si quelqu'un lit jamais ceci ... mais afin de ne pas retourner une liste d'objets type dans mes méthodes Clone, j'ai créé une interface:
Ensuite, j'ai spécifié l'extension:
Et voici une implémentation de l'interface dans mon logiciel de marquage A / V. Je voulais que ma méthode Clone () retourne une liste de VidMark (tandis que l'interface ICloneable voulait que ma méthode retourne une liste d'objets):
Et enfin, l'utilisation de l'extension à l'intérieur d'une classe:
Quelqu'un l'aime? Des améliorations?
la source
Vous pouvez également simplement convertir la liste en un tableau à l'aide
ToArray
, puis cloner le tableau à l'aideArray.Clone(...)
. Selon vos besoins, les méthodes incluses dans la classe Array peuvent répondre à vos besoins.la source
Vous pouvez utiliser la méthode d'extension:
Vous pouvez cloner tous les objets en utilisant leurs membres de type valeur par exemple, considérez cette classe:
Remarque: si vous effectuez des modifications sur la copie (ou le clonage), cela n'affectera pas l'objet d'origine.
la source
Si vous avez besoin d'une liste clonée avec la même capacité, vous pouvez essayer ceci:
la source
J'ai créé moi-même une extension qui convertit ICollection d'éléments qui n'implémentent pas IClonable
la source
J'utilise automapper pour copier un objet. Je viens de configurer un mappage qui mappe un objet sur lui-même. Vous pouvez terminer cette opération comme vous le souhaitez.
http://automapper.codeplex.com/
la source
L'utilisation d'un casting peut être utile, dans ce cas, pour une copie superficielle:
appliqué à la liste générique:
la source
Pour une copie complète, ICloneable est la bonne solution, mais voici une approche similaire à ICloneable utilisant le constructeur au lieu de l'interface ICloneable.
vous aurez besoin de la bibliothèque suivante où vous faites la copie
vous pouvez également utiliser une boucle for au lieu de System.Linq, mais Linq la rend concise et propre. De même, vous pouvez faire comme d'autres réponses l'ont suggéré et créer des méthodes d'extension, etc., mais rien de tout cela n'est nécessaire.
la source
Le code suivant doit être transféré sur une liste avec un minimum de modifications.
Fondamentalement, cela fonctionne en insérant un nouveau nombre aléatoire à partir d'une plus grande plage avec chaque boucle successive. S'il existe déjà des nombres qui sont identiques ou supérieurs à lui, déplacez ces nombres aléatoires d'un pour qu'ils soient transférés dans la nouvelle gamme plus large d'index aléatoires.
la source
Autre chose: vous pouvez utiliser la réflexion. Si vous le cachez correctement, il clonera 1 000 000 d'objets en 5,6 secondes (malheureusement, 16,4 secondes avec des objets internes).
Je l'ai mesuré d'une manière simple, en utilisant la classe Watcher.
RÉSULTAT: avec l'objet interne PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory est juste ma classe de test où j'ai une douzaine de tests, y compris l'utilisation de l'expression. Vous pouvez l'implémenter sous une autre forme dans une extension ou autre. N'oubliez pas la mise en cache.
Je n'ai pas encore testé la sérialisation, mais je doute d'une amélioration avec un million de classes. Je vais essayer quelque chose de rapide protobuf / newton.
PS: par souci de simplicité de lecture, je n'ai utilisé ici que la propriété automatique. Je pourrais mettre à jour avec FieldInfo, ou vous devriez facilement l'implémenter par vous-même.
J'ai récemment testé le sérialiseur Protocol Buffers avec la fonction DeepClone prête à l'emploi. Il gagne avec 4,2 secondes sur un million d'objets simples, mais en ce qui concerne les objets intérieurs, il gagne avec le résultat 7,4 secondes.
RÉSUMÉ: Si vous n'avez pas accès aux cours, cela vous aidera. Sinon, cela dépend du nombre d'objets. Je pense que vous pouvez utiliser la réflexion jusqu'à 10 000 objets (peut-être un peu moins), mais pour plus que cela, le sérialiseur Protocol Buffers fonctionnera mieux.
la source
Il existe un moyen simple de cloner des objets en C # à l'aide d'un sérialiseur et désérialiseur JSON.
Vous pouvez créer une classe d'extension:
Pour cloner et objecter:
la source