Using AutoMapper to Match a String to an Enumeration

I have a class of classes and Dto classes:

public class Profile { public string Name { get; set; } public string SchoolGrade { get; set; } } public class ProfileDTO { public string Name { get; set; } public SchoolGradeDTO SchoolGrade { get; set; } } public enum SchoolGradeDTO { [Display(Name = "Level One"] LevelOne, [Display(Name = "Level Two"] LevelTwo, } 

I used the following method:

  Mapper.CreateMap<Profile, ProfileDTO>() .ForMember(d => d.SchoolGrade , op => op.MapFrom(o => o.SchoolGrade)) 

Subsequently, I get the following error:

The requested value "Level 2" was not found.

How to match it?

+6
source share
3 answers

Since you are displaying a display name, not an enumeration name, you need to create a custom mapping function to scan attributes to find an enumeration with that display name. You can use ResolveUsing instead of MapFrom to use a custom mapping function:

 Mapper.CreateMap<Profile, ProfileDTO>() .ForMember(d => d.SchoolGrade, op => op.ResolveUsing(o=> MapGrade(o.SchoolGrade))); public static SchoolGradeDTO MapGrade(string grade) { //TODO: function to map a string to a SchoolGradeDTO } 

You can cache names in a static dictionary so you don't use reflection every time.

Several ways to do this can be found here .

+12
source

Turning around to D Stanley , answer a little higher and change the EnumHelper class from this other discussion to focus on yours since this question really covers two areas, AutoMapper and getting the Enum value from the string correctly.

Gain D Stanley's original answer:

 public static class QuestionAutoMapperConfig { public static void ConfigureAutoMapper() { Mapper.CreateMap<Profile, ProfileDTO>() .ForMember(d => d.SchoolGrade, op => op.ResolveUsing(o => MapGrade(o.SchoolGrade))); } public static SchoolGradeDTO MapGrade(string grade) { //TODO: function to map a string to a SchoolGradeDTO return EnumHelper<SchoolGradeDTO>.Parse(grade); } } 

I adjusted EnumHelper from the above example to quickly show a parameter in which you can modify the Parse method to try the standard Enum.Parse () first, and not get an attempt to make a more detailed comparison of Enum, creating a dictionary of values ​​based either on the name of the enumeration name , or the attribute text is displayed on it (if used).

 public static class EnumHelper<T> { public static IDictionary<string, T> GetValues(bool ignoreCase) { var enumValues = new Dictionary<string, T>(); foreach (FieldInfo fi in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public)) { string key = fi.Name; var display = fi.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[]; if (display != null) key = (display.Length > 0) ? display[0].Name : fi.Name; if (ignoreCase) key = key.ToLower(); if (!enumValues.ContainsKey(key)) enumValues[key] = (T)fi.GetRawConstantValue(); } return enumValues; } public static T Parse(string value) { T result; try { result = (T)Enum.Parse(typeof(T), value, true); } catch (Exception) { result = ParseDisplayValues(value, true); } return result; } private static T ParseDisplayValues(string value, bool ignoreCase) { IDictionary<string, T> values = GetValues(ignoreCase); string key = null; if (ignoreCase) key = value.ToLower(); else key = value; if (values.ContainsKey(key)) return values[key]; throw new ArgumentException(value); } } 
+6
source

in display configuration

 { CreateMap<string, CUSTOM_ENUM>().ConvertUsing<StringToEnumConverter<CUSTOM_ENUM>>(); } 

converters

 public class StringToEnumConverter<T> : ITypeConverter<string, T>, ITypeConverter<string, T?> where T : struct { public T Convert(ResolutionContext context) { T t; if (Enum.TryParse(source, out t)) { return t; } var source = (string)context.SourceValue; if (StringToEnumBase<T>.HasDisplayAttribute()) { var result = StringToEnumBase<T>.Parse(source); return result; } throw new ConverterException(); } T? ITypeConverter<string, T?>.Convert(ResolutionContext context) { var source = (string)context.SourceValue; if (source == null) return null; return Convert(context); } } public static class StringToEnumBase<T> where T:struct { public static T Parse(string str) { var type = typeof (T); var enumMembers = type.GetMembers(BindingFlags.Public | BindingFlags.Static); var enumMembersCollection = enumMembers .Select(enumMember => new { enumMember, attributes = enumMember.GetCustomAttributes(typeof(DisplayAttribute), false) }) .Select(t1 => new { t1, value = ((DisplayAttribute) t1.attributes[0]).Name }) .Select(t1 => new Tuple<string, string>(t1.value, t1.t1.enumMember.Name)) .ToList(); var currentMember = enumMembersCollection.FirstOrDefault(item => item.Item1 == str); if (currentMember == null) throw new ConverterException(); T t; if (Enum.TryParse(currentMember.Item2, out t)) { return t; } throw new ConverterException(); } public static bool HasDisplayAttribute() { var type = typeof (T); var attributes = type.GetCustomAttributes(typeof(DisplayAttribute), false); return attributes.Length > 0; } } 
0
source

Source: https://habr.com/ru/post/983325/


All Articles