Получить значение перечисления на основе значения имени XmlEnumAttribute - PullRequest
17 голосов
/ 15 июня 2010

Мне нужна функция Generic для получения имени или значения перечисления на основе свойства перечисления XmlEnumAttribute «Name».Например, у меня определено следующее перечисление:

Public Enum Currency
   <XmlEnum("00")> CDN = 1
   <XmlEnum("01")> USA= 2
   <XmlEnum("02")> EUR= 3
   <XmlEnum("03")> JPN= 4
End Enum

Первое значение перечисления в валюте равно 1;имя enum - "CDN";и значение свойства XMLEnumAttribute Name равно "00".

Если у меня есть значение enum, я могу получить значение XmlEnumAttribute "Name", используя следующую обобщенную функцию:

Public Function GetXmlAttrNameFromEnumValue(Of T)(ByVal pEnumVal As T) As String

        Dim type As Type = pEnumVal.GetType
        Dim info As FieldInfo = type.GetField([Enum].GetName(GetType(T), pEnumVal))
        Dim att As XmlEnumAttribute = CType(info.GetCustomAttributes(GetType(XmlEnumAttribute), False)(0), XmlEnumAttribute) 'If there is an xmlattribute defined, return the name

        Return att.Name
    End Function

Итак, используяВ приведенной выше функции я могу указать тип перечисления Currency, передать значение 1, и возвращаемое значение будет равно «00».

Что мне нужно, так это функция, которую нужно выполнить, если она противоположна.Если у меня есть значение имени XmlEnumAttribute «00», мне нужна функция для возврата перечисления Currency со значением 1. Точно также полезной была бы функция, которая возвращала бы имя перечисления «CDN».Затем я мог бы просто разобрать это, чтобы получить значение enum.

Любая помощь будет принята с благодарностью.

Ответы [ 5 ]

17 голосов
/ 19 июня 2010

Требование решить ту же самую проблему привело меня к этому вопросу и ответу. По мере разработки в VB.NET я переписывал решение CkH в VB и модифицировал его для использования вашей функции GetXmlAttrNameFromEnumValue.

Public Shared Function GetCode(Of T)(ByVal value As String) As T
    For Each o As Object In System.Enum.GetValues(GetType(T))
        Dim enumValue As T = CType(o, T)
        If GetXmlAttrNameFromEnumValue(Of T)(enumValue).Equals(value, StringComparison.OrdinalIgnoreCase) Then
            Return CType(o, T)
        End If
    Next

    Throw New ArgumentException("No code exists for type " + GetType(T).ToString() + " corresponding to value of " + value)
End Function

C # Версия:

public static string GetXmlAttrNameFromEnumValue<T>(T pEnumVal)
{
    // http://stackoverflow.com/q/3047125/194717
    Type type = pEnumVal.GetType();
    FieldInfo info = type.GetField(Enum.GetName(typeof(T), pEnumVal));
    XmlEnumAttribute att = (XmlEnumAttribute)info.GetCustomAttributes(typeof(XmlEnumAttribute), false)[0];
    //If there is an xmlattribute defined, return the name

    return att.Name;
}
public static T GetCode<T>(string value)
{
    // http://stackoverflow.com/a/3073272/194717
    foreach (object o in System.Enum.GetValues(typeof(T)))
    {
        T enumValue = (T)o;
        if (GetXmlAttrNameFromEnumValue<T>(enumValue).Equals(value, StringComparison.OrdinalIgnoreCase))
        {
            return (T)o;
        }
    }

    throw new ArgumentException("No XmlEnumAttribute code exists for type " + typeof(T).ToString() + " corresponding to value of " + value);
}
7 голосов
/ 15 июня 2010

Я делаю что-то похожее с пользовательскими атрибутами и использую этот метод для получения EnumValue на основе значения атрибута. GetStringValue - мой пользовательский метод, подобный вашему примеру выше.

public static class Enums 
{ 
    public static T GetCode<T>(string value) 
    { 
        foreach (object o in System.Enum.GetValues(typeof(T))) 
        { 
            if (((Enum)o).GetStringValue().Equals(value, StringComparison.OrdinalIgnoreCase))
                return (T)o; 
        } 
        throw new ArgumentException("No code exists for type " + typeof(T).ToString() + " corresponding to value of " + value); 
    } 
}  

Для всего процесса, который я использую, проверьте этот пост и ответы: Расширение Enums, Overkill?

Извините, это в C #, только что понял, что вы используете VB.NET выше.

3 голосов
/ 12 ноября 2012

Слегка изменено с: http://www.wackylabs.net/2006/06/getting-the-xmlenumattribute-value-for-an-enum-field/

public static string ToString2 (this Enum e) {
    // Get the Type of the enum
    Type t = e.GetType ();

    // Get the FieldInfo for the member field with the enums name
    FieldInfo info = t.GetField (e.ToString ("G"));

    // Check to see if the XmlEnumAttribute is defined on this field
    if (!info.IsDefined (typeof (XmlEnumAttribute), false)) {
        // If no XmlEnumAttribute then return the string version of the enum.
        return e.ToString ("G");
    }

    // Get the XmlEnumAttribute
    object[] o = info.GetCustomAttributes (typeof (XmlEnumAttribute), false);
    XmlEnumAttribute att = (XmlEnumAttribute)o[0];
    return att.Name;
}
2 голосов
/ 14 июля 2016

Вот вариант, который генерирует словарь из перечисления, что позволяет вам потенциально кэшировать его часть отражения, если вам нужно много ее использовать.

/// <summary>
/// Generates a dictionary allowing you to get the csharp enum value
/// from the string value in the matching XmlEnumAttribute.
/// You need this to be able to dynamically set entries from a xsd:enumeration
/// when you've used xsd.exe to generate a .cs from the xsd.
/// https://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.110).aspx
/// </summary>
/// <typeparam name="T">The xml enum type you want the mapping for</typeparam>
/// <returns>Mapping dictionary from attribute values (key) to the actual enum values</returns>
/// <exception cref="System.ArgumentException">T must be an enum</exception>
private static Dictionary<string, T> GetEnumMap<T>() where T : struct, IConvertible
{
        if (!typeof(T).IsEnum)
        {
                throw new ArgumentException("T must be an enum");
        }
        var members = typeof(T).GetMembers();
        var map = new Dictionary<string, T>();
        foreach (var member in members)
        {
                var enumAttrib = member.GetCustomAttributes(typeof(XmlEnumAttribute), false).FirstOrDefault() as XmlEnumAttribute;
                if (enumAttrib == null)
                {
                        continue;
                }
                var xmlEnumValue = enumAttrib.Name;
                var enumVal = ((FieldInfo)member).GetRawConstantValue();
                map.Add(xmlEnumValue, (T)enumVal);
        }
        return map;
}

использование:

var map = GetEnumMap<Currency>();
return map["02"]; // returns Currency.EUR
1 голос
/ 24 мая 2012

@ Дин, @Jason и @Camron, спасибо за ваши решения.Ваши решения помогли мне в решении моей проблемы, где, учитывая имя XmlEnumAttribute, было необходимо фактическое значение перечисления.

Мой вариант упоминается здесь .

Я такжевключив его здесь, как это было задано одним из наших модераторов:

Реальная проблема заключалась в том, как получить Item10, когда ему дано значение 10. Принимая подсказку из решения, процитированного нашими вышеупомянутыми друзьями, я подошелс помощью следующего метода, который при передаче значения, содержащегося в XmlEnumAttribute, возвращает значение перечисления:

private static T GetEnumValueFromXmlAttrName<T>(string attribVal)
{
    T val = default(T);

    if (typeof(T).BaseType.FullName.Equals("System.Enum"))
    {
        FieldInfo[] fields = typeof(T).GetFields();

        foreach (FieldInfo field in fields)
        {
            object[] attribs = field.GetCustomAttributes(typeof(XmlEnumAttribute), false);

            foreach (object attr in attribs)
            {
                if ((attr as XmlEnumAttribute).Name.Equals(attribVal))
                {
                    val = (T)field.GetValue(null);
                    return val;
                }
            }
        }
    }
    else
        throw new Exception("The supplied type is not an Enum.");

    return val;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...