Как мне клонировать общий список в C #?

Вы попали в ловушку с использованием записей.

Рассмотрите этот код:

function Test: TTest;
begin
    ...
end;

Test.a := 1;

Что ваш код выглядит как компилятор, на самом деле это:

TTest temp := Test;
temp.a := 1;

Компилятор сообщает вам, с сообщением об ошибке, что назначение бессмысленно, поскольку оно будет присваивать новое значение только временному значению записи, которое будет немедленно забыто.

Кроме того, @List[10] недействителен, потому что List[10] снова возвращает только временное значение записи, поэтому запись адреса этой записи является довольно бессмысленной.

Однако чтение и запись всей записи в порядке.

Итак, чтобы подвести итог:

List[10] := A;  <- writing a whole record is OK
List[10].a:=1;  <- List[10] returns a temporary record, pointless assignment
P:=@List[10];   <- List[10] returns a temporary record, its address is pointless
526
задан Peter Mortensen 3 December 2012 в 06:26
поделиться

5 ответов

Можно использовать дополнительный метод.

static class Extensions
{
    public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
    {
        return listToClone.Select(item => (T)item.Clone()).ToList();
    }
}
351
ответ дан nawfal 3 December 2012 в 06:26
поделиться

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

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.

Любая из этих опций могла быть обернута методом (расширение или иначе).

463
ответ дан Jeff Yates 3 December 2012 в 06:26
поделиться

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

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

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

Заключенный в кавычки из: Рецепты Дженериков

75
ответ дан Jochem Broekhoff 3 December 2012 в 06:26
поделиться
  • 1
    У Вас есть ссылка на Вашу статью? Или ссылка где-нибудь? – coryan 4 April 2009 в 13:49

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

И Вы знаете тип:

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);
14
ответ дан Lucas B 3 December 2012 в 06:26
поделиться
  • 1
    Для Win32 я рекомендовал бы LoadLibraryEx с набором флага LOAD_WITH_ALTERED_SEARCH_PATH. – dalle 2 April 2009 в 06:48
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()]. Цель состоит в том, чтобы потерять все ссылки и создать новые.

77
ответ дан bluish 3 December 2012 в 06:26
поделиться
  • 1
    идея состоит в том, что при изменении базового класса он может повредить все производные классы - однако, я думаю, что это относится ко всем oo плагинам. Это, конечно, относится к jscript.net: blogs.msdn.com/ericlippert/archive/2004/01/07/… – gbjbaanb 4 April 2009 в 14:08
Другие вопросы по тегам:

Похожие вопросы: