2012-06-29 2 views
29

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

Mapper.CreateMap<Contract_1_1_0.ValidationResultType, Common.ValidationResultType>(); 

Когда это не сработало, я попробовал:

Mapper.CreateMap<Contract_1_1_0.ValidationResultType, Common.ValidationResultType>().ConvertUsing(x => (Common.ValidationResultType)((int)x)); 

Но это, кажется, не работает. Есть ли способ заставить automapper обрабатывать этот сценарий?

+0

У вас возникла ошибка? Что не сработало? –

+0

Я получил «конфигурацию карты отсутствующего типа или неподдерживаемое отображение». ошибка. –

+3

Можете ли вы разместить свои перечисления? –

ответ

33

Вам не нужно создавать CreateMap для типов перечислений. Просто избавитесь от вызова CreateMap, и он должен работать, если имена и/или значения совпадают между типами перечислений.

+0

Когда вы будете следовать этой практике, она будет адаптироваться с использованием значения перечисления или имени члена? –

+9

Что делать, если имена и значения не совпадают? – Darcy

+1

Затем вам нужно создать конвертер пользовательского типа. –

2

Вот одна возможность для преобразования между двумя типами Enum, которые имеют разные значения, при этом все еще используется AutoMapper. В моем случае мне нужно было использовать AutoMapper, потому что типы Enum были свойствами для других объектов, преобразованных AutoMapper; использование AutoMapper для этих объектов было требованием.

Первым шагом является настройка конфигурации Mapper следующим образом:

Mapper.CreateMap<EnumSrc, EnumDst>() 
    .ConstructUsing(EnumConversion.FromSrcToDst); 

Вызов .ConstructUsing(...) позволяет нам перейти в наш собственный метод для создания преобразования. Способ преобразования является довольно прямо вперед:

public class EnumConversion 
{ 
    internal static EnumDst FromSrcToDst(ResolutionContext arg) 
    { 
     EnumSrc value = (EnumSrc)arg.SourceValue; 
     switch(value) 
     { 
      case EnumSrc.Option1: 
       return EnumDst.Choice1; 
      case EnumSrc.Option2: 
       return EnumDst.Choice2; 
      case EnumSrc.Option3: 
       return EnumDst.Choice3; 
      default: 
       return EnumDst.None; 
     } 
    } 
} 

Мы просто switch через значения исходного Enum и возвращает соответствующее значение целевой Enum произвольно. AutoMapper заботится обо всем остальном.

+1

Я пробовал эту реализацию, и она просто отображается на основе целочисленного значения (AutoMapper 3.3.1). Я добавлю свой ответ, который работал ниже – Neil

2

Другие ответы здесь не помогли мне.

Вам нужно создать класс, который реализует:

ITypeConvertor<SourceType ,DestinationType> 

Так как пример

Mapper.CreateMap<EnumType1.VatLevel, EnumType2.VatRateLevel>() 
     .ConvertUsing(VatLevelConvertor); 

и класс:

internal class VatLevelConvertor : ITypeConverter<EnumType1.VatLevel, EnumType2.VatRateLevel> 
{ 
    public EnumType2.VatRateLevel Convert(ResolutionContext context) 
    { 
     EnumType1.VatLevel value = (EnumType1.VatLevel)context.SourceValue; 
     switch (value) 
     { 
      case EnumType1.VatLevel.Standard: 
       return EnumType2.VatRateLevel.Normal; 
      case EnumType1.VatLevel.Reduced: 
       return EnumType2.VatRateLevel.Lower; 
      case EnumType1.VatLevel.SuperReduced: 
       return EnumType2.VatRateLevel.Other; 
      default: 
       return EnumType2.VatRateLevel.Other; 
     } 
    } 
} 
28

В качестве альтернативы для написания пользовательских преобразователей, просто использовать ConvertUsing()

Mapper.CreateMap<EnumSrc, EnumDst>().ConvertUsing(value => 
{ 
    switch(value) 
    { 
     case EnumSrc.Option1: 
      return EnumDst.Choice1; 
     case EnumSrc.Option2: 
      return EnumDst.Choice2; 
     case EnumSrc.Option3: 
      return EnumDst.Choice3; 
     default: 
      return EnumDst.None; 
    } 
}); 
4

Самый простой способ я нашел, что работа для меня, как показано ниже:

Мой Enum является вложенным в другом классе, поэтому я использую метод ForMember и MapFrom, как показано ниже:

Mapper.CreateMap<ProblematicCustomer, ProblematicCustomerViewModel>()     
      .ForMember(m=> m.ProblemType, opt=> opt.MapFrom(x=> (ProblemTypeViewModel)(int)x.ProblemType)) 
      .ForMember(m=> m.JudgmentType, opt=> opt.MapFrom(x=> (JudgmentTypeViewModel)(int)x.JudgmentType)); 

The ProblemType и JudgmentType это перечисления. И связанные с ними модели для просмотра - это модели ProblemTypeViewModel и JudgmentTypeViewModel с теми же элементами, что и связанные с ними модели.

Хотя я не испытываю, но я думаю, что ниже линии должны работать для вас:

Mapper.CreateMap<Contract_1_1_0.ValidationResultType, Common.ValidationResultType>() 
      .ForMember(m=> m, opt => opt.MapFrom(x=> (Common.ValidationResultType)(int)x); 

Надежда это поможет.

2

Я пытался сопоставить «равные» перечисления с помощью Automapper, но, к сожалению, это не сработало. Я подозреваю, что проблема есть разница в корпусе:

public enum Foo { 
    val1, 
    val2 
} 

public enum Bar { 
    Val1, 
    Val2 
} 

Foo что-то автоматически генерируется из XSD, и поставщик сосет. Также есть тридцать-то значений, и я не хотел ставить switch, что это большое место для чего-то такого глупого.

Подхода, который я взял был преобразовать значение источника в строку и разобрать, что в качестве места назначения:

static Foo ConvertEnum(Bar source) 
{ 
    Foo result; 
    var parsed = Enum.TryParse(source.ToString().ToLowerInvariant(), true, out result); 
    if(!parsed) 
     // throw or return default value 
     throw new ArgumentOutOfRangeException("source", source, "Unknown source value"); 
    return result; 
} 

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

2

Просто создайте карту для двух Enums, вот и все! Automapper будет отображать либо значение соответствия, либо значение индекса Enum. (Например, проект -> Step1)

public enum SourceStatus 
{ 
    Draft, 
    Submitted, 
    Deleted 
} 

public enum DestinationStatus 
{ 
    Step1, 
    Step2, 
    Step3 
} 

public class SourceObj 
{ 
    public SourceStatus Status { get; set; } 
} 

public class DestinationObj 
{ 
    public DestinationStatus Status { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     //Static APi style - this is obsolete now. From Version 5.0 onwards this will be removed. 
     SourceObj mySrcObj = new SourceObj(); 
     mySrcObj.Status = SourceStatus.Deleted; 

     Mapper.CreateMap<SourceStatus, DestinationStatus>(); 
     Mapper.CreateMap<SourceObj, DestinationObj>(); 

     DestinationObj myDestObj = Mapper.Map<SourceObj, DestinationObj>(mySrcObj); 

     //New way of doing it 
     SourceObj mySrcObj2 = new SourceObj(); 
     mySrcObj2.Status = SourceStatus.Draft; 

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

     IMapper mapper = config.CreateMapper(); 
     var source = new SourceObj(); 
     var dest = mapper.Map<SourceObj, DestinationObj>(source); 



    } 
} 
6

Мои Automapper работает следующим образом:

Если создать карту: Automapper будет соответствовать перечислений по значению, даже если матч имя отлично.

Если я не создаю карту: Automapper будет соответствовать перечислениям по имени.

Смежные вопросы