AutoMapper Как Сопоставить Объект A Объекту B По-Разному В Зависимости От Контекста

вызов всех гуру AutoMapper!

Я хотел бы иметь возможность сопоставлять объект A объекту B по-разному в зависимости от контекста во время выполнения. В частности, я хотел бы игнорировать определенные свойства в одном случае отображения и иметь все свойства, отображаемые в другом случае.

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

Я нашел сообщение в блоге, которое защищает картографа.Reset () чтобы обойти проблему, однако, статический характер класса Mapper означает, что это только вопрос времени, прежде чем произойдет столкновение и сбой.

есть ли способ сделать это?

думаю, мне нужно позвонить картографу.CreateMap один раз в appdomain, а затем, быть в состоянии вызвать Mapper.Карта с подсказками о какие свойства следует включить / исключить.

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

Каковы мои варианты. Что можно сделать? Automapper кажется таким многообещающим.

3 ответов


класс Mapper-это просто тонкая оболочка поверх объектов конфигурации и MappingEngine. Вы можете создавать отдельные экземпляры объектов Configuration / MappingEngine (все еще используя синглеты) и использовать выбранный контейнер IoC для загрузки правильного по мере необходимости.

лучшим вариантом по-прежнему является использование различных типов назначения. Действительно трудная часть о действительно поддержке этой функции-неотъемлемая иерархическая природа карт типов. Объект верхнего уровня может есть профиль отображения, в то время как более низкие уровни не делают. Некоторые между ними, возможно это или нет и т. д.


просто в дополнение к ответу Джимми вот код, необходимый для использования AutoMapper без статического Mapper

начиная с версии 4.2.1 Automapper имеет санкционированный нестатический картограф и конфигурацию (спасибо Джимми!).

var config = new MapperConfiguration(cfg => {
    cfg.CreateMap<ClassA, ClassB>();
});

var mapper = config.CreateMapper();

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

(правильный для версии 4.1.1)

// Configuration
AutoMapper.Mappers.MapperRegistry.Reset();
var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);
autoMapperCfg.Seal();

//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();

var b = mappingEngine.Map<ClassB>(a);

(верно для версии 3.2.1)

// Configuration
var platformSpecificRegistry = AutoMapper.Internal.PlatformAdapter.Resolve<IPlatformSpecificMapperRegistry>();
platformSpecificRegistry.Initialize();

var autoMapperCfg = new AutoMapper.ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);

//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();

var b = mappingEngine.Map<ClassB>(a);

(верно для версии 2.2.1)

// Configuration
var autoMapperCfg = new AutoMapper.ConfigurationStore(new AutoMapper.TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.AllMappers());
var mappingEngine = new AutoMapper.MappingEngine(autoMapperCfg);

//Usage example
autoMapperCfg.CreateMap<ClassA, ClassB>();

var b = mappingEngine.Map<ClassB>(a);

для меня это звучит как лучший дизайн, возможно, иметь несколько классов назначения (возможно, наследование от общей базы или реализация общего интерфейса)

Если свойства unmapped никогда не будут использоваться в одном из вариантов, вы можете полностью оставить их (давая гарантию времени компиляции, что они не используются по ошибке), выбросить исключение, когда к ним обращаются (не так хорошо, как гарантия времени компиляции, но иногда вам нужен полный интерфейс реализовано) или даже использовать заменяющее значение.

например:

public class Source
{
    public string Name {get;set;}
    public BigEntity {get;set;}

    /* other members */
}

public class SourceDTO
{
    public string Name {get;set;}
    public BigEntity {get;set;}
}

public class SourceSummaryDTO
{
    public string Name {get;set;}
}

в качестве альтернативы вы можете сделать следующее:

public class SourceSummaryDTO : SourceDTO
{
    public string Name {get;set;}
    public BigEntity 
    {
        get{throw new NotSupportedException();}
        set{throw new NotSupportedException();}
    }
}

таким образом, Вы можете передать SourceSummaryDTO, как если бы это был SourceDTO.

наличие условно заполненных свойств звучит как рецепт для неприятностей для меня - я бы предпочел иметь классы, которые явны о том, что они содержат, особенно с объектами передачи данных.

для меня, самое лучшее о Automapper возможность проверки сопоставлений, а затем знать, что каждое свойство в целевых классах будет заполнено.