Cloner avec de meilleures performances

Je veux créer une méthode de copie en profondeur et j’ai trouvé 3 façons de l’exécuter

Copie 1 profondeur avec passe chaque propriété 1 par 1

2-utilisant la reflection

3 en utilisant la sérialisation

s’il vous plaît lequel d’entre eux est le meilleur au niveau des performances

La première option, la copie manuelle en profondeur de vos valeurs, sera de loin la plus performante.

La reflection introduira un peu de surcharge, car il est (relativement) lent pour accéder aux données.

La sérialisation représente un coût énorme, car elle sérialise les données dans une structure temporaire, puis inverse le processus à définir. C’est encore très lent.

Le seul avantage de l’option 2 ou 3 est qu’il est potentiellement plus facile à mettre en œuvre et qu’il peut être réutilisé pour plusieurs types. La première option doit être écrite à la main par type, mais elle est beaucoup plus rapide (et plus efficace en termes d’utilisation de la mémoire que l’option 3 également).

J’ai fait un graphique avec la comparaison des trois méthodes plus une méthode des arbres d’expression.

entrez la description de l'image ici

La reflection est 5 fois plus rapide pour un grand nombre d’objects et les arbres de code et d’expression manuels sont 20 fois plus rapides que la sérialisation. Les meilleurs résultats sont donc le code manuel et les arbres d’expression.

Liens vers les codes de clonage utilisés (2.-4. Utilisés comme méthode d’extension):

  1. Manuel : écrit manuellement, pas de lien.
  2. Clonage par sérialisation
  3. Clonage par reflection
  4. Clonage par les arbres d’expression

Ordre que vous avez énuméré vos solutions possibles est ordre de performance correct.

Vous obtiendrez de meilleures performances lorsque vous écrivez le code pour cloner manuellement chaque valeur de propriété.

La reflection aura un résultat similaire à celui du clonage manuel, mais un peu plus lent.

La sérialisation est le pire des scénarios. Mais le plus rapide à mettre en œuvre.

Voici un bon article qui décrit d’autres solutions possibles.

Voici donc une liste de toutes les méthodes de clonage possibles:

  1. Cloner manuellement
  2. Cloner avec MemberwiseClone
  3. Cloner avec reflection
  4. Cloner avec la sérialisation
  5. Cloner avec IL
  6. Cloner avec des méthodes d’extension

Personnellement, je choisirais ” Clone with IL “, car il est légèrement plus rapide que la reflection et vous n’avez pas à tout cloner manuellement.

Le meilleur pour la performance est la création du clone dans votre code. Donc le chemin “1”.

Il y a l’interface ICloneable . Si le clonage est réalisable, l’utilisation de ses méthodes serait la meilleure solution

On dirait que vous avez fait le dur travail pour trouver les moyens de le faire, vous devez donc maintenant les tester dans votre situation spécifique et les découvrir.

Pour la plupart, cela dépend vraiment des données que vous sérialisez

Reflection peut être utilisé pour produire DynamicMethod, ce qui peut être plus efficace que la copie manuelle (les propriétés automatiques peuvent être copiées en accédant à des champs ouvrant directement la scope via skipVisibilityCheck). DynamicMethod vous propose un délégué que vous pouvez conserver dans un champ statique en lecture seule pour cloner votre object. C’est le moyen rapide et facile de le faire mais pas forcément le plus propre. La sérialisation est lente et non adaptée.

En tant qu’auteur de CGbR, j’aimerais vous inviter à l’essayer pour votre cas d’utilisation.

Tout ce dont vous avez besoin, c’est du paquet de pépites et d’une définition de classe partielle qui implémente ICloneable . Le fichier généré créera ensuite un fichier avec une méthode Clone(bool deep) .

 public partial class Root : ICloneable { public Root(int number) { _number = number; } private int _number; public Partial[] Partials { get; set; } public IList Numbers { get; set; } public object Clone() { return Clone(true); } private Root() { } } public partial class Root { public Root Clone(bool deep) { var copy = new Root(); // All value types can be simply copied copy._number = _number; if (deep) { // In a deep clone the references are cloned var tempPartials = new Partial[Partials.Length]; for (var i = 0; i < Partials.Length; i++) { var value = Partials[i]; value = value.Clone(true); tempPartials[i] = value; } copy.Partials = tempPartials; var tempNumbers = new List(Numbers.Count); for (var i = 0; i < Numbers.Count; i++) { var value = Numbers[i]; tempNumbers[i] = value; } copy.Numbers = tempNumbers; } else { // In a shallow clone only references are copied copy.Partials = Partials; copy.Numbers = Numbers; } return copy; } } 

Performance: Dans un DataContractSerializer performance pour un clone, nous avions besoin au travail de le comparer à DataContractSerializer et MemoryStream . Le code généré est 600x plus rapide.