2016-03-10 4 views
1

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

Вот упрощение моих классов:

public class FooContainerDTO 
{ 
    public FooDTO Foo { get; set; } 
} 

public class FooDTO 
{ 
    public string Type { get; set; } 

    //some properties.. 
} 

public class FooContainer 
{ 
    public FooBase Foo { get; set; } 
} 

public abastract class FooBase 
{ 
    //some properties.. 
} 

public class FooDerived1 : FooBase 
{ 
    //some properties 
} 

public class FooDerived2 : FooBase 
{ 
    //some properties 
} 

Я использую нестатический Automapper поэтому я создаю MapperConfiguration из нескольких профилей при загрузке и впрыснуть экземпляр IMapper в мой DI-контейнер. Я хочу, чтобы Automapper отображал FooDTO в FooDerived1, когда его свойство типа «der1» и FooDerived2, когда оно «der2».

Я видел примеры на этот счет, используя статический API, что-то вроде этого:

Mapper.CreateMap<FooContainerDTO, FooContainer>(); 
     //ForMember configurations etc. 

Mapper.CreateMap<FooDTO, FooDerived1>(); 
     //ForMember configurations etc. 

Mapper.CreateMap<FooDTO, FooDerived2>(); 
     //ForMember configurations etc. 

Mapper.CreateMap<FooDTO, FooBase>() 
     .ConvertUsing(dto => dto.Type == "der1" 
      ? (FooBase) Mapper.Map<FooDerived1>(dto) 
      : Mapper.Map<FooDerived2>(dto)); 

Это карта свойство Foo из FooContainer к правильному производного типа FooBase.

Но как я могу это сделать без статического API? Экземпляр IMapper еще не создан в момент настройки профиля. Есть ли способ использовать перегрузку ConvertUsing(), которая принимает Func < ResolutionContext, object>? Может ли контекст разрешения дать мне то, что в настоящее время используется IMapper? Я искал, но не могу найти ничего полезного.

+0

Итак, как ни странно, я использовал для этого немного временного взлома. У меня есть собственный класс TypeConverter, который содержит 'IMapper _defaultEngine = MyGlobalConfig.Engine'. Затем я создаю две конфигурации: одну, использующую статический глобальный, и другую, которую я размещаю в своем собственном статическом местоположении и использую в качестве «резервной» для более простых сопоставлений. –

+0

Это, вероятно, работает, но «взломать» - это правильное имя :) Я немного взломал себя, чтобы заставить его работать; вместо того, чтобы вставлять сам IMapper в DI, я добавляю экземпляр MapperContainer, который имеет свойство удерживать фактический экземпляр IMapper. Затем я могу ввести MapperContainer в свой профиль и настроить ConvertUsing-lambdas для доступа к свойству mapper, даже если он будет NULL до тех пор, пока bootstrapper не установит экземпляр IMapper. –

+0

На самом деле, снова глядя на вашу проблему, почему вы не можете просто создать TypeConverter и использовать 'ResolutionContext.Engine.Map' внутри' Convert'? –

ответ

2

Один из способов получить доступ к картографическому двигателю через свой собственный TypeConverter

abstract class MyTypeConverter<TSource,TDestination> : ITypeConverter<TSource, TDestination> 
{ 
    protected ResolutionContext context; 
    public TDestination Convert(ResolutionContext context) 
    { 
     this.context = context; 
     return Convert((TSource)context.SourceValue); 
    } 
    public abstract TDestination Convert(TSource source); 
} 

Вы затем создать фактическую реализацию, как:

class MyTypeMapper : MyTypeConverter<EnumType,EnumTypeView> 
{ 
    public override EnumTypeView Convert(EnumType source) 
    { 
     return context.Engine.Mapper.Map<EnumTypeID, EnumTypeView>(source.EnumBaseType); 
    } 
} 

За исключением вместо разворачивания структуры перечислимой, вы» d проверьте тип и вызовите карту с разными типами.

+0

Ваш код не компилируется для меня (Automapper 4.2), но с использованием 'context.Engine.Mapper.Map (context.SourceValue)', похоже, делает трюк! Только то, что я искал! Благодаря! –

+0

К сожалению, пропущено это, исправлено. Рад, что это работает! –

+0

Кроме того, мне не нужно создавать TypeMapper, используя 'Engine.Mapper' из лямбда в' ConvertUsing (Func func) ', похоже, работает нормально. –