Как глубоко клонировать объекты, содержащие свойство IList, используя AutoMapper
Я пытаюсь глубоко клонировать следующий класс, используя AutoMapper:
public class MainData
{
public MainData()
{
Details = new List<Detail>();
}
public int Id { get; private set; }
public DateTime LastUpdate { get; private set; }
public IList<Detail> Details { get; private set; }
public int Prop1 { get; set; }
public int Prop2 { get; set; }
public void AddDetail(Detail detail)
{
Details.Add(detail);
}
public void RemoveDetail(Detail detail)
{
Details.Remove(detail);
}
public MainData Clone()
{
Mapper.Reset();
Mapper.CreateMap<MainData, MainData>().ForMember(d => d.Id, o => o.Ignore());
// Mapper.CreateMap<Detail, Detail>().ForMember(d => d.Id, o => o.Ignore()); // REMOVED
var newMainData = new MainData();
Mapper.Map(this, newMainData);
newMainData.Details = this.Details.Select(item => item.Clone()).ToList(); // ADDED
return newMainData;
}
}
public class Detail
{
public int Id { get; private set; }
public string Name { get; set; }
public double Area { get; set; }
public double Height { get; set; }
public Detail Clone() // ADDED
{
Mapper.CreateMap<Detail, Detail>().ForMember(d => d.Id, o => o.Ignore());
var newDetail = new Detail();
Mapper.Map(this, newDetail);
return newDetail;
}
}
Метод Clone
отлично работает для свойств MainData, но, похоже, делает только мелкую копию списка деталей. Я попытался добавить .ForMember(d => d.Details, o => o.UseDestinationValue())
, но это не копирует список сведений вообще. Как я могу получить список деталей, также сильно клонированный, т.е. Я получаю два полностью независимых объекта, включая все элементы списка?
UPDATE: Мне нужно исключить свойство Id, поскольку я использую эти объекты с NHibernate, поэтому не уверен, что это сделает решение Serializable.
UPDATE2: Изменен приведенный выше код для клонирования IList. Кажется, это работает нормально, поскольку я могу исключить свойства, которые делают NHibernate, как он уже был сохранен.
Ответы
Ответ 1
здесь есть одно решение с ValueInjecter
var clone = new MainData();
clone.InjectFrom(mainData);//mainData is your source
mainData.Details.AsParallel.ForAll(detail =>
{
var dc = new Detail();
dc.InjectFrom(detail);
clone.AddDetail(dc);
});
свойства, у которых есть частные сеттеры, не будут установлены (выглядит разумно)
удачи;)
EDIT:
Я нашел лучшее решение здесь
Ответ 2
AutoMapper на самом деле не является клонирующим API. Вместо этого я использовал бы этот клонирующий трюк:
public static object CloneObject(object obj)
{
using (MemoryStream memStream = new MemoryStream())
{
BinaryFormatter binaryFormatter = new BinaryFormatter(null,
new StreamingContext(StreamingContextStates.Clone));
binaryFormatter.Serialize(memStream, obj);
memStream.Seek(0, SeekOrigin.Begin);
return binaryFormatter.Deserialize(memStream);
}
}
Это не работает для каждой ситуации, но это очень удобно.