Как глубоко клонировать объекты, содержащие свойство 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, но, похоже, делает только мелкую копию списка Details. Я пробовал добавить .ForMember(d => d.Details, o => o.UseDestinationValue()), но это вообще не копирует список "Подробности". Как я могу получить глубокое клонирование списка Details, т.е. так, чтобы я получил два полностью независимых объекта, включая все элементы списка?

ОБНОВЛЕНИЕ: мне нужно исключить свойство Id, поскольку я использую эти объекты с NHibernate, поэтому не уверен, что решение Serializable сделает это.

ОБНОВЛЕНИЕ 2: приведенный выше код был изменен, чтобы также клонировать IList. Кажется, это работает нормально, поскольку я могу исключить свойства, которые заставляют NHibernate думать, что он уже сохранен.


person Piers Myers    schedule 03.08.2010    source источник


Ответы (2)


вот одно решение с 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);
        });

свойства, у которых есть частные сеттеры, не будут установлены, (выглядит разумно)
удачи;)

РЕДАКТИРОВАТЬ: я сделал лучшее решение, посмотрите здесь

person Omu    schedule 03.08.2010
comment
Очень хорошая библиотека, работает хорошо. Пришлось изменить часть PLINQ на цикл ForEach, поскольку я еще не использую .NET 4. - person Piers Myers; 04.08.2010
comment
@Piers Myers, я сделал что-то более общее для клонирования, вы можете увидеть это здесь valueinjecter .codeplex.com / - person Omu; 08.02.2011

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);
    }
}

Это работает не для каждой ситуации, но довольно удобно.

person Jimmy Bogard    schedule 03.08.2010
comment
спасибо, я встречал это решение несколько раз в своих поисках, но не был уверен, что хочу сделать все свои классы сериализуемыми. Метод Automapper выглядел бы довольно элегантно, если бы я смог заставить его работать так, как я хочу. - person Piers Myers; 03.08.2010
comment
это популярный хак для клонирования. к сожалению, это приводит к всевозможным проблемам, связанным с сериализацией / десериализацией. Я надеялся, что AutoMapper будет более прямолинейным :) - person Sonic Soul; 07.12.2017