C# 使用AutoMapper将字符串映射到枚举
我有以下类域和Dto类:C# 使用AutoMapper将字符串映射到枚举,c#,.net,automapper,C#,.net,Automapper,我有以下类域和Dto类: 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 Sc
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,
}
我使用了以下方法:
Mapper.CreateMap<Profile, ProfileDTO>()
.ForMember(d => d.SchoolGrade , op => op.MapFrom(o => o.SchoolGrade))
Mapper.CreateMap()
.FormMember(d=>d.SchoolGrade,op=>op.MapFrom(o=>o.SchoolGrade))
之后,我得到以下错误:
找不到请求的值“级别2”
如何正确映射它?因为您是从显示名称而不是从枚举名称映射,所以您需要构建一个自定义映射函数来扫描属性以查找具有该显示名称的枚举。您可以使用
ResolveUsing
而不是MapFrom
来使用自定义映射功能:
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
}
Mapper.CreateMap()
.FormMember(d=>d.学校年级,
op=>op.ResolveUsing(o=>MapGrade(o.SchoolGrade));
公立静态学校等级到地图等级(字符串等级)
{
//TODO:将字符串映射到学校成绩数据的函数
}
您可以将名称缓存在静态字典中,这样就不会每次都使用反射
可以找到一些方法。从上面更详细地扩展Stanley的回答,并修改了,以关注您的具体情况,因为这个问题实际上涉及两个方面:自动映射和从字符串正确获取枚举值 增强斯坦利的原始答案:
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);
}
}
公共静态类QuestionAutoMapperConfig
{
公共静态无效配置自动映射()
{
Mapper.CreateMap()
.FormMember(d=>d.学校年级,
op=>op.ResolveUsing(o=>MapGrade(o.SchoolGrade));
}
公立静态学校等级到地图等级(字符串等级)
{
//TODO:将字符串映射到学校成绩数据的函数
返回EnumHelper.Parse(grade);
}
}
我已经调整了上述示例中的EnumHelper,以快速显示一个选项,在该选项中,您可以修改Parse方法以首先尝试标准Enum.Parse(),如果失败,则尝试通过创建基于枚举值名称的值字典来对枚举类型进行更详细的比较,或者它的显示属性文本(如果使用)
公共静态类EnumHelper
{
公共静态IDictionary GetValues(bool ignoreCase)
{
var enumValues=新字典();
foreach(类型为(T).GetFields的FieldInfo fi(BindingFlags.Static | BindingFlags.Public))
{
string key=fi.Name;
var display=fi.GetCustomAttributes(typeof(DisplayAttribute),false)作为DisplayAttribute[];
如果(显示!=null)
key=(display.Length>0)?display[0]。名称:fi.Name;
如果(忽略案例)
key=key.ToLower();
如果(!enumValues.ContainsKey(键))
enumValues[key]=(T)fi.GetRawConstantValue();
}
返回枚举值;
}
公共静态T解析(字符串值)
{
T结果;
尝试
{
result=(T)Enum.Parse(typeof(T),value,true);
}
捕获(例外)
{
结果=ParseDisplayValues(值,true);
}
返回结果;
}
私有静态T parseDisplayValue(字符串值,bool ignoreCase)
{
IDictionary values=GetValues(ignoreCase);
字符串键=null;
如果(忽略案例)
key=value.ToLower();
其他的
键=值;
if(值。容器(键))
返回值[键];
抛出新ArgumentException(值);
}
}
映射配置中的
{
CreateMap<string, CUSTOM_ENUM>().ConvertUsing<StringToEnumConverter<CUSTOM_ENUM>>();
}
{
CreateMap().ConvertUsing();
}
转换器
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;
}
}
公共类StringToEnumConverter:ITypeConverter,ITypeConverter其中T:struct
{
公共T转换(ResolutionContext上下文)
{
T;
if(枚举TryParse(源,out t))
{
返回t;
}
var source=(string)context.SourceValue;
if(StringToEnumBase.HasDisplayAttribute())
{
var result=StringToEnumBase.Parse(源代码);
返回结果;
}
抛出新的ConverterException();
}
转换(ResolutionContext上下文)
{
var source=(string)context.SourceValue;
if(source==null)返回null;
返回转换(上下文);
}
}
公共静态类StringToEnumBase,其中T:struct
{
公共静态T解析(字符串str)
{
var类型=类型(T);
var enumMembers=type.GetMembers(BindingFlags.Public | BindingFlags.Static);
var enumMembersCollection=enumMembers
.选择(enumMember=>new
{
委员:,
attributes=enumMember.GetCustomAttributes(typeof(DisplayAttribute),false)
})
.选择(t1=>新建
{
t1,值=((DisplayAttribute)t1.attributes[0]).Name
})
.Select(t1=>newtuple(t1.value,t1.t1.enumMember.Name))
.ToList();
var currentMember=enumMembersCollection.FirstOrDefault(item=>item.Item1==str);
如果(currentMember==null)抛出新的ConverterException();
T;
if(枚举TryParse(currentMember.Item2,out t))
{
返回t;
}
抛出新的ConverterException();
}
公共静态bool HasDisplayAttribute()
{
var类型=类型(T);
var attributes=type.GetCustomAttributes(typeof(DisplayAttribute),false);
返回属性。长度>0;
}
}
传递枚举的显示属性值的原因是什么?也就是说,你为什么
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;
}
}