Преобразование иерархии сложных вложенных объектов с помощью Automapper

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

Классы отображения:

public class Instance
{
    public Type Type { get; set; }
    public object Definition { get; set; }
}

public sealed class Class : Instance
{
    private IList<Property> m_Properties;
    public IList<Property> Properties
    {
        get { return m_Properties ?? (m_Properties = new List<Property>()); }
    }
}

public abstract class Member : Instance
{
    public string Name { get; set; }
}

public sealed class Parameter : Member
{
}

public sealed class Property : Member
{
}

Обратите внимание, что Instanceкласс имеет Definitionсвойство type object, которое будет содержать Classссылку, поэтому вложенная иерархия будет начинаться отсюда до N уровней. Я преобразовывал нормально, но свойство Definition внутри Classи его вложенные объекты иерархии все еще держали ссылку на источник вместо цели. После добавления ForMember(t => t.Definition, opt => opt.MapFrom(s => Mapper.Map<Source.Class, Target.Class>((Source.Class)s.Definition)))to make this transformation work some, он начал давать исключение.

Использование:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Source.Member, Target.Member>()
                .Include<Source.Property, Target.Property>()
                .Include<Source.Parameter, Target.Parameter>()
                .ForMember(t => t.Definition, opt => opt.MapFrom(s => Mapper.Map<Source.Class, Target.Class>((Source.Class)s.Definition)));

    cfg.CreateMap<Source.Property, Target.Property>();
    cfg.CreateMap<Source.Parameter, Target.Parameter>();
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();

var definitionLevel1 = new Source.Class();
definitionLevel1.Properties.Add(new Source.Property() { Name = "PropertyLevel_1.1" });
definitionLevel1.Properties.Add(new Source.Property() { Name = "PropertyLevel_1.2" });

var definitionLevel2 = new Source.Class();
definitionLevel2.Properties.Add(new Source.Property() { Name = "PropertyLevel_2.1" });
definitionLevel1.Definition = definitionLevel2;

Source.Member sourceMember = new Source.Property()
{
    Name = "Some_Property_Name",
    Definition = definitionLevel1,
    Type = typeof(CompositeType)
};

IEnumerable<Source.Member> sourceMembers = new List<Source.Member>() { sourceMember };
var targetMembers = mapper.Map<IEnumerable<Target.Member>>(sourceMembers);

Пожалуйста, помогите мне заполнить пробелы или недостающие части.

1 ответ

  1. Ahhh наконец, я решил эту сложную проблему, до сих пор результаты кажутся прекрасными, но предложения использовать еще лучшую практику (если таковые имеются) приветствуются, поскольку я новичок и только начал использовать Automapper.

    Поэтому ниже приведены конфигурации с соответствующими картографами.

    Конфигурация:

    IMapper memberMapper = null;
    IMapper classMapper = null;
    
    var classConfig = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Source.Class, Target.Class>()
            .ForMember(t => t.Properties, opt => opt.MapFrom(s => memberMapper.Map<IList<Target.Property>>(s.Properties)))
            .ForMember(t => t.Definition, opt => opt.MapFrom(s => classMapper.Map<Source.Class, Target.Class>((Source.Class)s.Definition)));
        cfg.CreateMap<Source.Property, Target.Property>();
    });
    classConfig.AssertConfigurationIsValid();
    classMapper = classConfig.CreateMapper();
    
    var memberConfig = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Source.Member, Target.Member>()
            .Include<Source.Property, Target.Property>()
            .Include<Source.Parameter, Target.Parameter>()
            .ForMember(t => t.Definition, opt => opt.MapFrom(s => classMapper.Map<Source.Class, Target.Class>((Source.Class)s.Definition)));
    
        cfg.CreateMap<Source.Property, Target.Property>();
        cfg.CreateMap<Source.Parameter, Target.Parameter>();
    });
    memberConfig.AssertConfigurationIsValid();
    memberMapper = memberConfig.CreateMapper();
    

    Идея, которую я использовал, заключается в том, что два картографа работают вместе в соответствии с их областью действия, чтобы получить это отображение рекурсивно.