簡體   English   中英

使用 AutoMapper 將字符串映射到枚舉

[英]Using AutoMapper to map a string to an enum

我有以下類域和 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,
}

我使用了以下方法:

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

之后,我收到以下錯誤:

未找到請求的值“二級”。

我如何正確映射它?

由於您是從顯示名稱而不是枚舉名稱進行映射,因此您需要構建一個自定義映射函數來掃描屬性以查找具有該顯示名稱的枚舉。 您可以使用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
}

您可以將名稱緩存在靜態字典中,這樣您就不會每次都使用反射。

可以在這里找到一些這樣做的方法。

從上面更詳細地擴展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);
    }
}

我已經從提到的示例中調整了 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);
    }
}

在映射配置中

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

轉換器

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;
            }
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM