У меня есть общий список объектов в C#, и я хочу клонировать этот список. Элементы внутри списка могут быть клонированы, но, похоже, нет возможности сделать list.Clone()
.
Есть ли простой способ обойти это?
Если ваши элементы являются типами значений, то вы можете просто сделать:
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.
List<int> oldList = new List<int>( );
// Populate oldList...
List<int> newList = oldList.GetRange(0, oldList.Count);
Цитируется по: Generics Recipes
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# и .Объем 2.0. Ваш объект требует, чтобы быть [сериализуемые()]
. Цель состоит в том, чтобы потерять все ссылки и строить новые.
После небольшой модификации вы можете также клонировать:
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;
}
Клонировать список просто позвоните .Список()
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 }
>
Если вам нужно реальное клон каждого отдельного объекта внутри вашего список в <Т>
, лучший способ для копирования списка, чтобы создать новый список со старым список в качестве параметра коллекции.
List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);
Изменения в класса MyList
, такие как вставка или удаление не повлияет на cloneOfMyList
и наоборот.
Однако сами объекты этих двух списков содержат все те же.
Если вы заботитесь только о типах значений...
И вы знаете тип:
List<int> newList = new List<int>(oldList);
Если вы не знаете тип, вам понадобится вспомогательная функция:
List<T> Clone<T>(IEnumerable<T> oldList)
{
return newList = new List<T>(oldList);
}
{{376573}}:
List<string> myNewList = Clone(myOldList);
Использовать AutoMapper (или как сопоставление Либ вы предпочитаете) для клонирования проста и много ремонтопригодны.
Определите соответствия:
Mapper.CreateMap<YourType, YourType>();
Делать магию:
YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);
Если у вас уже имеется ссылка Newtonsoft.JSON в ваш проект и ваши объекты можно сериализовать вы всегда можете использовать:
List<T> newList = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(listToCopy))
Возможно, не самый эффективный способ сделать это, но если вы're делая их 100S из 1000 раз, вы можете даже не заметить разницы в скорости.
//try this
List<string> ListCopy= new List<string>(OldList);
//or try
List<T> ListCopy=OldList.ToList();
public List<TEntity> Clone<TEntity>(List<TEntity> o1List) where TEntity : class , new()
{
List<TEntity> retList = new List<TEntity>();
try
{
Type sourceType = typeof(TEntity);
foreach(var o1 in o1List)
{
TEntity o2 = new TEntity();
foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
{
var val = propInfo.GetValue(o1, null);
propInfo.SetValue(o2, val);
}
retList.Add(o2);
}
return retList;
}
catch
{
return retList;
}
}
public static Object CloneType(Object objtype)
{
Object lstfinal = new Object();
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
binaryFormatter.Serialize(memStream, objtype); memStream.Seek(0, SeekOrigin.Begin);
lstfinal = binaryFormatter.Deserialize(memStream);
}
return lstfinal;
}
Я'll быть счастливый если кто-нибудь когда-нибудь прочтет это... но для того, чтобы не возвращать список объектов типа в моих методах клон, я создал интерфейс:
public interface IMyCloneable<T>
{
T Clone();
}
Затем я указал расширение:
public static List<T> Clone<T>(this List<T> listToClone) where T : IMyCloneable<T>
{
return listToClone.Select(item => (T)item.Clone()).ToList();
}
А вот реализация интерфейса на моем а/V маркировка программного обеспечения. Я хотел, чтобы мой клон() метод возвращает список VidMark (в то время как интерфейс ICloneable хотел, чтобы мой метод, чтобы возвратить список объектов):
public class VidMark : IMyCloneable<VidMark>
{
public long Beg { get; set; }
public long End { get; set; }
public string Desc { get; set; }
public int Rank { get; set; } = 0;
public VidMark Clone()
{
return (VidMark)this.MemberwiseClone();
}
}
И, наконец, использование расширения внутри класса:
private List<VidMark> _VidMarks;
private List<VidMark> _UndoVidMarks;
//Other methods instantiate and fill the lists
private void SetUndoVidMarks()
{
_UndoVidMarks = _VidMarks.Clone();
}
Кто-нибудь нравится? Каких-либо улучшений?
Вы также можете просто преобразовать список в массив, используя метод toArray
, а затем клонировать массива с помощью массива.Клон(...)`.
В зависимости от ваших потребностей, методы, входящие в класс Array может удовлетворить ваши потребности.
Вы можете использовать метод расширения:
namespace extension
{
public class ext
{
public static List<double> clone(this List<double> t)
{
List<double> kop = new List<double>();
int x;
for (x = 0; x < t.Count; x++)
{
kop.Add(t[x]);
}
return kop;
}
};
}
Вы можете клонировать все объекты с помощью своих членов типом значения например, рассмотрим следующий класс:
public class matrix
{
public List<List<double>> mat;
public int rows,cols;
public matrix clone()
{
// create new object
matrix copy = new matrix();
// firstly I can directly copy rows and cols because they are value types
copy.rows = this.rows;
copy.cols = this.cols;
// but now I can no t directly copy mat because it is not value type so
int x;
// I assume I have clone method for List<double>
for(x=0;x<this.mat.count;x++)
{
copy.mat.Add(this.mat[x].clone());
}
// then mat is cloned
return copy; // and copy of original is returned
}
};
Примечание: Если вы делаете любые изменения на копия (или Клон) это не повлияет на исходный объект.
Если вам нужно клонировать список с той же мощности, вы можете попробовать это:
public static List<T> Clone<T>(this List<T> oldList)
{
var newList = new List<T>(oldList.Capacity);
newList.AddRange(oldList);
return newList;
}
Мой друг Грегор Мартиновича и я придумал простое решение с помощью JavaScript сериализатор. Нет необходимости занятия флаг как сериализуемый и в наших тестах, используя Newtonsoft JsonSerializer даже быстрее, чем используя класс binaryformatter. С методов расширения полезной для каждого объекта.
Стандарт .Вариант чистый класс javascriptserializer:
public static T DeepCopy<T>(this T value)
{
JavaScriptSerializer js = new JavaScriptSerializer();
string json = js.Serialize(value);
return js.Deserialize<T>(json);
}
Быстрее с помощью Newtonsoft JSON с:
public static T DeepCopy<T>(this T value)
{
string json = JsonConvert.SerializeObject(value);
return JsonConvert.DeserializeObject<T>(json);
}
Я использую automapper, чтобы скопировать объект. Я просто настроить отображение карты одного объекта на себя. Вы можете обернуть эту операцию любым удобным для вас способом.