Question Comment cloner une liste générique en C #?


J'ai une liste générique d'objets en C #, et souhaite cloner la liste. Les éléments de la liste sont clonables, mais il ne semble pas y avoir d'option list.Clone().

Y a-t-il un moyen facile de contourner cela?


465
2017-10-21 16:47


origine


Réponses:


Vous pouvez utiliser une méthode d'extension.

static class Extensions
{
    public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
    {
        return listToClone.Select(item => (T)item.Clone()).ToList();
    }
}

313
2017-10-21 16:58



Si vos éléments sont des types de valeur, vous pouvez simplement faire:

List<YourType> newList = new List<YourType>(oldList);

Cependant, si ce sont des types de référence et que vous voulez une copie profonde (en supposant que vos éléments sont correctement implémentés) ICloneable), vous pourriez faire quelque chose comme ceci:

List<ICloneable> oldList = new List<ICloneable>();
List<ICloneable> newList = new List<ICloneable>(oldList.Count);

oldList.ForEach((item) =>
    {
        newList.Add((ICloneable)item.Clone());
    });

Évidemment remplacer ICloneable dans les génériques ci-dessus et cast avec quel que soit votre type d'élément qui implémente ICloneable.

Si le type d'élément ne prend pas en charge ICloneable mais possède un constructeur de copie, vous pouvez le faire à la place:

List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);

oldList.ForEach((item)=>
    {
        newList.Add(new YourType(item));
    });

Personnellement, j'éviterais ICloneable en 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 comme YourType.CopyFrom(YourType itemToCopy) qui renvoie une nouvelle instance de YourType.

Chacune de ces options pourrait être enveloppée par une méthode (extension ou autre).


411
2017-10-21 16:54



public static object DeepClone(object obj) 
{
  object objResult = null;
  using (MemoryStream  ms = new MemoryStream())
  {
    BinaryFormatter  bf =   new BinaryFormatter();
    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 être [Serializable()]. L'objectif est de perdre toutes les références et d'en construire de nouvelles.


70
2017-10-21 17:43



Pour une copie superficielle, vous pouvez utiliser à la place la méthode GetRange de la classe List générique.

List<int> oldList = new List<int>( );
// Populate oldList...

List<int> newList = oldList.GetRange(0, oldList.Count);

Cité de: Recettes génériques


61
2017-10-21 16:52



Après une légère modification, vous pouvez également cloner:

public static T DeepClone<T>(T obj)
{
    T objResult;
    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, obj);
        ms.Position = 0;
        objResult = (T)bf.Deserialize(ms);
    }
    return objResult;
}

19
2017-07-20 09:26



Utilisez AutoMapper (ou tout autre mappage que vous préférez) pour cloner est simple et facile à gérer.

Définissez votre mapping:

Mapper.CreateMap<YourType, YourType>();

Faites la magie

YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);

12
2018-02-13 23:20



Si vous ne vous souciez que des types de valeur ...

Et vous connaissez le type:

List<int> newList = new List<int>(oldList);

Si vous ne connaissez pas le type avant, vous aurez besoin d'une fonction d'assistance:

List<T> Clone<T>(IEnumerable<T> oldList)
{
    return newList = new List<T>(oldList);
}

Le juste:

List<string> myNewList = Clone(myOldList);

12
2017-10-21 16:54



Pour cloner une liste, appelez simplement .ToList ()

Microsoft (R) Roslyn C# Compiler version 2.3.2.62116
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> var x = new List<int>() { 3, 4 };
> var y = x.ToList();
> x.Add(5)
> x
List<int>(3) { 3, 4, 5 }
> y
List<int>(2) { 3, 4 }
> 

11
2017-09-25 00:35