使用AutoMapper将字符串映射到枚举

gog*_*gog 13 .net c# automapper

我有以下类domain和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 SchoolGradeDTO 
{
   [Display(Name = "Level One"]
   LevelOne,
   [Display(Name = "Level Two"]
   LevelTwo,
}
Run Code Online (Sandbox Code Playgroud)

我使用以下方法:

 Mapper.CreateMap<Profile, ProfileDTO>()
       .ForMember(d => d.SchoolGrade , op => op.MapFrom(o => o.SchoolGrade))
Run Code Online (Sandbox Code Playgroud)

之后,我收到以下错误:

未找到请求的值"二级".

如何正确映射?

D S*_*ley 16

由于您要从显示名称而不是枚举名称进行映射,因此您需要使用自定义映射函数来扫描属性以查找具有该显示名称的枚举.您可以使用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
}
Run Code Online (Sandbox Code Playgroud)

您可以将名称缓存在静态字典中,这样您就不会每次都使用反射.

可以在此处找到一些这样做的方法.

  • 注意:升级到 AutoMapper 8 后,“ResolveUsing”必须替换为“MapFrom”。请参阅 https://docs.automapper.org/en/stable/8.0-Upgrade-Guide.html?highlight=resolveusing。 (7认同)

小智 8

更详细地扩展了D Stanley从上面得到的答案,并从其他讨论中修改了EnumHelper类,专注于您的具体情况,因为这个问题确实跨越了两个方面,AutoMapper并正确地从字符串中获取Enum的值.

加强D 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经从提到的示例中调整了EnumHelper以快速显示一个选项,您可以通过修改Parse方法来首先尝试标准的Enum.Parse(),并且无法通过创建来尝试对Enum类型进行更详细的比较基于枚举值名称的值的字典,或者是显示属性文本(如果使用的话).

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);
    }
}
Run Code Online (Sandbox Code Playgroud)