Ответ 1
Вам не нужно создавать CreateMap для типов перечислений. Просто избавитесь от вызова CreateMap и он должен работать, если имена и/или значения совпадают между типами перечисления.
У меня есть открытый интерфейс, который я пытаюсь сопоставить двум различным перечислениям друг с другом. Я попытался использовать следующий код:
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 обрабатывать этот сценарий?
Вам не нужно создавать CreateMap для типов перечислений. Просто избавитесь от вызова CreateMap и он должен работать, если имена и/или значения совпадают между типами перечисления.
В качестве альтернативы написанию пользовательских преобразователей просто используйте 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;
}
});
My Automapper работает следующим образом:
Если я создаю карту: Automapper будет соответствовать перечислениям по значению, даже если имя идеально соответствует.
Если я не создаю карту: Automapper будет соответствовать перечислениям по имени.
Самый простой способ Я нашел, что работа для меня такова:
My 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));
TypeType и JudgmentType - это перечисления. И связанные с ними модели для просмотра - это модели ProblemTypeViewModel и JudgmentTypeViewModel с теми же элементами, что и связанные с ними модели.
Хотя я не тестирую, но я думаю, что ниже строка должна работать для вас:
Mapper.CreateMap<Contract_1_1_0.ValidationResultType, Common.ValidationResultType>()
.ForMember(m=> m, opt => opt.MapFrom(x=> (Common.ValidationResultType)(int)x);
Надеюсь, что это поможет.
Здесь есть одна возможность для преобразования между двумя типами 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 заботится обо всем остальном.
Другие ответы здесь не спомогли мне.
Вам нужно создать класс, который реализует:
ITypeConvertor<SourceType ,DestinationType>
Так в качестве примера
Mapper.CreateMap<EnumType1.VatLevel, EnumType2.VatRateLevel>()
.ConvertUsing(new 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;
}
}
}
Просто создайте картограф для двух Enums, чтобы он! Automapper будет отображать либо значение соответствия, либо значение индекса Enum. (например, Черновик → Шаг 1)
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);
}
}
Я пытался сопоставить "равные" перечисления с помощью 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;
}
Конечно, это работает только в том случае, если ваши перечисления имеют только различия в корпусе. Вы можете сделать его более сложным, очистив входную строку (например, удалите символы подчеркивания и т.д.) Или добавив к ней материал по мере необходимости.