如何从StringValue属性的值解析枚举

时间:2019-06-04 04:31:11

标签: c# .net .net-core

无法从其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枚举对象?

5 个答案:

答案 0 :(得分:2)

这应该做到:

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

答案 1 :(得分:1)

我将创建一个反向查询字典,该字典采用枚举值并返回匹配的枚举值:

public static void main(String[] args) {
    int input[] = {1, 3, 9, 6, 5, 8, 3, 4};
    Map<Integer, Integer> valueMap = new HashMap<>(); 
    for (int i = 0; i < input.length - 1; i++) {
        for (int j = i + 1; j < input.length; j++) {
            if (9 - input[i] == input[j]) {
                if((valueMap.containsKey(input[i])&&valueMap.containsValue(input[j])) || (valueMap.containsKey(input[j])&&valueMap.containsValue(input[i]))) {                          
                    //these are repetitive values
                } else {
                    valueMap.put(input[i], input[j]);
                    System.out.println("[" + input[i] + ", " + input[j] + "]");
                }
            }
        }
    }
}

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

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

Try it online

答案 2 :(得分:1)

您的呼叫代码:

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的定义不同,请随时更新您的问题以包括该类型定义,并且如有必要,我将更新我的答案。

答案 3 :(得分:0)

我为此创建了一种方法

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;

        }

答案 4 :(得分:0)

只需最小的更改即可完成工作:

实用程序类:

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