【问题标题】:How to parse enum from value of StringValue attribute如何从 StringValue 属性的值解析枚举
【发布时间】:2019-06-04 04:31:11
【问题描述】:

无法从其 StringValue 属性解析为枚举对象。

枚举:

public enum StatusColor
{
    [StringValue("#FFFFFF")]
    None,

    [StringValue("#5DB516")]
    Green,

    [StringValue("#F3212A")]
    Red,

    [StringValue("#FFFFFF")]
    White
}

解析尝试1

string inputHtmlColor = "#F3212A"; // input
StatusColor outColor; // output
Enum.TryParse(inputHtmlColor , true, out outColor);

解析尝试2:

string inputHtmlColor = "#F3212A"; //input
StatusColor outColor = Enum.Parse(typeof(StatusColor), inputHtmlColor, true);

两个代码都不起作用,代码总是选择StausColor.None(第一个)。如何获得正确的 StatusColor 枚举对象?

【问题讨论】:

  • 如果链接的问题没有回答你的问题,请告诉我(通过在评论中标记我@john),我会重新打开你的问题。
  • 嗨@John,你建议的答案与我想要的相反。答案是关于从对象到它的属性值,而我已经有了属性值并且我将它转换为枚举对象。
  • @kame [ ] 表示attribute
  • 嗨@kame,[ ] 类似于Java 中的@ 注解,如果您有Java 背景的话。
  • 我今天刚做了这个。搜索“convert to enum from description attribute”并更改代码以使用该属性。

标签: c# .net .net-core


【解决方案1】:

应该这样做:

public StatusColor GetColor(string color)
{
    return
        Enum.GetValues(typeof(StatusColor))
            .Cast<StatusColor>()
            .First(x => ((StringValueAttribute)typeof(StatusColor)
                        .GetField(x.ToString())
                        .GetCustomAttribute(typeof(StringValueAttribute))).Value == color);
}

【讨论】:

    【解决方案2】:

    我会创建一个反向查找字典,它接受枚举值并返回匹配的枚举值:

    public static IDictionary<TKey, TEnum> GetReverseEnumLookup<TEnum, TKey, TAttribute>(Func<TAttribute, TKey> selector, IEqualityComparer<TKey> comparer = null)
        where TEnum: struct, IConvertible // pre-C#7.3
        // where TEnum : System.Enum // C#7.3+
        where TAttribute: System.Attribute
    {
        // use the default comparer for the dictionary if none is specified
        comparer = comparer ?? EqualityComparer<TKey>.Default;
    
        // construct a lookup dictionary with the supplied comparer
        Dictionary<TKey, TEnum> values = new Dictionary<TKey, TEnum>(comparer);
    
        // get all of the enum values
        Type enumType = typeof(TEnum);
        var enumValues = typeof(TEnum).GetEnumValues().OfType<TEnum>();
    
        // for each enum value, get the corresponding field member from the enum
        foreach (var val in enumValues)
        {
            var member = enumType.GetMember(val.ToString()).First();
    
            // if there is an attribute, save the selected value and corresponding enum value in the dictionary
            var attr = member.GetCustomAttribute<TAttribute>();
            if (attr != null) 
            {
                values[selector(attr)] = val;
            }
        }
        return values;
    }
    

    我已使此方法尽可能通用,以便它可以应用于许多用例。在您的情况下,用法如下所示:

    var lookup = GetReverseEnumLookup<StatusColor, string, StringValueAttribute>(v => v.Value, StringComparer.OrdinalIgnoreCase); // I figure you want this to be case insensitive
    

    然后您可以将查找静态存储在某处,并像这样查找值:

    StatusColor color;
    if (lookup.TryGetValue("#ffffff", out color))
    {
        Console.WriteLine(color.ToString());
    }
    else
    {
        // not found
    }
    

    Try it online

    【讨论】:

    • 嗨@John,不是一个直截了当的答案,但我真的很喜欢与 Dictionary 建立关系并查看它的想法。可能我会创建自己的,并且为了不区分大小写,我会通过将关键案例转换为我存储的相同来查看。谢谢!
    • @δev 我只是认为您可能需要某种程度的性能(字典会提供)。我不喜欢我见过的替代方法,因为它们经常在每次需要转换值时使用反射评估整个枚举。它有效,但效率不高。
    【解决方案3】:

    您的呼叫代码:

    string inputHtmlColor = "#F3212A";
    StatusColor outColor = inputHtmlColor.GetEnumFromString<StatusColor>();
    

    这就是您调用以下扩展方法的方式。

    • 我使用并修改了以下来自here的扩展方法
    public static class EnumEx
    {
        public static T GetEnumFromString<T>(this string stringValue)
        {
            var type = typeof(T);
            if (!type.IsEnum) throw new InvalidOperationException();
            foreach (var field in type.GetFields())
            {
                var attribute = Attribute.GetCustomAttribute(field,
                    typeof(StringValueAttribute)) as StringValueAttribute;
                if (attribute != null)
                {
                    if (attribute.Value == stringValue)
                        return (T)field.GetValue(null);
                }
                else
                {
                    if (field.Name == stringValue)
                        return (T)field.GetValue(null);
                }
            }
            throw new ArgumentException("Not found.", "stringValue");
            // or return default(T);
        }
    }
    

    属性说明:

    我这样定义我的属性:

    public class StringValueAttribute : Attribute
    {
        public string Value { get; private set; }
    
        public StringValueAttribute(string value)
        {
            Value = value;
        }
    }
    

    如果您的 StringValueAttribute 定义不同,请随时更新您的问题以包含该类型定义,如有必要,我会更新我的答案。

    【讨论】:

      【解决方案4】:

      我为此创建了一种方法,如下所示

      StringEnum.GetStringValue(Pass Your enum here)
      

      调用这个在普通类中创建的函数

      public static string GetStringValue(Enum value)
              {
                  string output = null;
                  try
                  {
                      Type type = value.GetType();
      
                      if (_stringValues.ContainsKey(value))
                          output = (_stringValues[value] as StringValueAttribute).Value;
                      else
                      {
                          ////Look for our 'StringValueAttribute' in the field's custom attributes
                          FieldInfo fi = type.GetField(value.ToString());
                          StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
                          if (attrs.Length > 0)
                          {
                              _stringValues.Add(value, attrs[0]);
                              output = attrs[0].Value;
                          }
      
                      }
                  }
                  catch (Exception)
                  {
      
                  }
      
                  return output;
      
              }
      

      【讨论】:

      • 嗨@rvchauhan,这不是我要找的。我已经有 GetStringValue 方法将对象转换为字符串 attrb 值。我想要正好相反。想要从字符串属性值到枚举对象。谢谢!
      【解决方案5】:

      这就是最小的变化:

      实用类:

      private static IDictionary<string, StatusColor> _statusColorByHtml = Enum.GetValues(typeof(StatusColor)).Cast<StatusColor>().ToDictionary(k => k.GetStringValue(), v => v);
      public static StatusColor GetStatusColor(string htmlColor)
      {
          _statusColorByHtml.TryGetValue(htmlColor, out StatusColor color);
          return color;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-31
        • 2021-07-15
        • 2011-02-16
        • 2016-02-21
        • 1970-01-01
        • 2013-11-04
        相关资源
        最近更新 更多