Вы попали в ловушку с использованием записей.
Рассмотрите этот код:
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
Можно использовать дополнительный метод.
static class Extensions
{
public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
{
return listToClone.Select(item => (T)item.Clone()).ToList();
}
}
Если Ваши элементы являются типами значения, то можно просто сделать:
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
.
Любая из этих опций могла быть обернута методом (расширение или иначе).
Для мелкой копии можно вместо этого использовать метод GetRange универсального класса Списка.
List<int> oldList = new List<int>( );
// Populate oldList...
List<int> newList = oldList.GetRange(0, oldList.Count);
Заключенный в кавычки из: Рецепты Дженериков
Если Вы только заботитесь о типах значения...
И Вы знаете тип:
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);
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()]
. Цель состоит в том, чтобы потерять все ссылки и создать новые.