Как мне клонировать общий список в C #? - PullRequest
518 голосов
/ 21 октября 2008

У меня есть общий список объектов в C #, и я хочу клонировать этот список. Элементы в списке являются клонируемыми, но, похоже, нет возможности сделать list.Clone().

Есть ли простой способ обойти это?

Ответы [ 26 ]

457 голосов
/ 21 октября 2008

Если ваши элементы являются типами значений, то вы можете просто сделать:

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

Однако, если они являются ссылочными типами и вы хотите глубокое копирование (при условии, что ваши элементы правильно реализуют ICloneable), вы можете сделать что-то вроде этого:

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

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

Очевидно, замените ICloneable в вышеприведенных обобщениях и приведите к типу элемента, который реализует ICloneable.

Если ваш тип элемента не поддерживает ICloneable, но имеет конструктор копирования, вы можете сделать это вместо этого:

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

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

Лично я бы избежал ICloneable из-за необходимости гарантировать глубокую копию всех участников. Вместо этого я бы предложил конструктор копирования или метод фабрики, такой как YourType.CopyFrom(YourType itemToCopy), который возвращает новый экземпляр YourType.

Любой из этих параметров может быть заключен в метод (расширение или иным образом).

345 голосов
/ 21 октября 2008

Вы можете использовать метод расширения.

static class Extensions
{
    public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
    {
        return listToClone.Select(item => (T)item.Clone()).ToList();
    }
}
76 голосов
/ 21 октября 2008
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 # и .NET 2.0. Ваш объект должен быть [Serializable()]. Цель состоит в том, чтобы потерять все ссылки и построить новые.

75 голосов
/ 21 октября 2008

Для мелкой копии вместо этого можно использовать метод GetRange универсального класса List.

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

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

Цитируется из: Общие рецепты

20 голосов
/ 20 июля 2011

После небольшой модификации вы также можете клонировать:

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;
}
18 голосов
/ 25 сентября 2017

Чтобы клонировать список, просто вызовите .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 }
> 
15 голосов
/ 10 июля 2015

Если вам не нужен фактический клон каждого отдельного объекта внутри List<T>, лучший способ клонировать список - создать новый список со старым списком в качестве параметра коллекции.

List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);

Изменения в myList, такие как вставка или удаление, не влияют на cloneOfMyList и наоборот.

Фактические объекты, содержащиеся в двух списках, все равно остаются теми же.

13 голосов
/ 14 февраля 2013

Использовать AutoMapper (или любую другую библиотеку картирования, которую вы предпочитаете), чтобы клонировать, это просто и много поддерживаемо

Определите ваше отображение:

Mapper.CreateMap<YourType, YourType>();

сотвори волшебство:

YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);
13 голосов
/ 21 октября 2008

Если вы заботитесь только о типах значений ...

А вы знаете тип:

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

Если вы раньше не знали тип, вам понадобится вспомогательная функция:

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

Просто:

List<string> myNewList = Clone(myOldList);
9 голосов
/ 01 ноября 2013

Если вы уже ссылались на Newtonsoft.Json в своем проекте и ваши объекты сериализуемы, вы всегда можете использовать:

List<T> newList = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(listToCopy))

Возможно, это не самый эффективный способ сделать это, но если вы не сделаете это 100 или 1000 раз, вы можете даже не заметить разницу в скорости.

...