简体   繁体   English

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

[英]How to parse enum from value of StringValue attribute

Not able to parse into enum object from its StringValue attribute. 无法从其StringValue属性解析为枚举对象。

enum: 枚举:

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

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

    [StringValue("#F3212A")]
    Red,

    [StringValue("#FFFFFF")]
    White
}

parsing try 1 解析尝试1

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

parsing try 2: 解析尝试2:

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

Both code is not working, codes always selecting StausColor.None (the first one). 这两个代码都不起作用,代码始终选择StausColor.None (第一个)。 How can I get the right StatusColor enum object? 如何获得正确的StatusColor枚举对象?

This should do it: 应该这样做:

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

I would create a reverse lookup dictionary that takes the enum value and returns a matching enum value: 我将创建一个反向查询字典,该字典采用枚举值并返回匹配的枚举值:

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

I've made this method as generic as possible so that it can apply to many use cases. 我已经使这种方法尽可能通用,以便可以应用于许多用例。 Usage in your case would look like this: 您的情况下的用法如下所示:

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

And then you can store the lookup statically somewhere, and lookup values like this: 然后,您可以将查找静态存储在某个地方,查找值如下所示:

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

Try it online 在线尝试

Your calling code: 您的呼叫代码:

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

That's how you would call the below extension method. 这就是调用以下扩展方法的方式。

  • I used and modified the below extension method which came from 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);
    }
}

note on the Attribute: 关于属性的注释:

I defined my attribute like this: 我这样定义属性:

public class StringValueAttribute : Attribute
{
    public string Value { get; private set; }

    public StringValueAttribute(string value)
    {
        Value = value;
    }
}

If your StringValueAttribute is defined differently, feel free to update your question to include that type definition, and I'll update my answer if necessary. 如果您的StringValueAttribute定义不同,请随时更新您的问题以包括该类型定义,如有必要,我将更新答案。

I have created one method for that as below 我为此创建了一种方法,如下所示

StringEnum.GetStringValue(Pass Your enum here)

Call this function which is created in common class 调用在普通类中创建的此函数

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;

        }

This what working with minimal change: 只需最小的更改即可工作:

Util class: 实用程序类:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM