Получить XmlEnumAttribute из перечисления

У меня есть перечисление:

public enum Operation {
    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("01")]
    Item01,

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("02")]
    Item02,

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("03")]
    Item03,

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("04")]
    Item04,
}

Как я могу получить значение XmlEnumAttribute?

Я пытаюсь:

var res = Operation.Item1;
var result = (res.GetType().GetField("Item01").GetCustomAttributes(typeof(XmlEnumAttribute), true)[0] as XmlEnumAttribute).Name;

Может быть лучший метод?

Ответ 1

Вы можете создать вспомогательный (статический) класс с помощью этого метода расширения

public static string GetXmlEnumAttributeValueFromEnum<TEnum>(this TEnum value) where TEnum : struct, IConvertible
{
    var enumType = typeof(TEnum);
    if (!enumType.IsEnum) return null;//or string.Empty, or throw exception

    var member = enumType.GetMember(value.ToString()).FirstOrDefault();
    if (member == null) return null;//or string.Empty, or throw exception

    var attribute = member.GetCustomAttributes(false).OfType<XmlEnumAttribute>().FirstOrDefault();
    if (attribute == null) return null;//or string.Empty, or throw exception
    return attribute.Name;
}

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

var res = Operation.Item1;
var result = res.GetXmlAttributeValueFromEnum();

Ответ 2

Вы должны использовать Reflection для получения значения атрибута:

var value = Operation.Item02;

var attributeValue = ((XmlEnumAttribute)typeof(Operation)
                        .GetMember(value.ToString())[0]
                        .GetCustomAttributes(typeof(XmlEnumAttribute), false)[0])
                        .Name;

Ответ 3

Спасибо; это полезно для меня. Я бы хотел расширить ответ рафаэля на более общий сценарий. Если код перечисления сгенерирован из xsd программой xsd.exe, не у каждого перечисления будет этот атрибут. Это может произойти, когда вы используете перечисления xsd для ограничения строк определенным списком значений, некоторые из которых имеют пробелы, а некоторые - нет. Например:

<xs:simpleType name="fooEnum">
 <xs:restriction base="xs:string">
  <xs:enumeration value="Foo Bar" />
  <xs:enumeration value="Bar Foo" />
  <xs:enumeration value="JustPlainFoo" />
 </xs:restriction>
</xs:simpleType>

выдаст код сериализации С#:

public enum fooEnum {

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("Foo Bar")]
    FooBar,

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("Bar Foo")]
    BarFoo,

    /// <remarks/>
    JustPlainFoo,
 }

В этом случае клиентский код, ожидающий "JustPlainFoo", не будет выполнен. Моя версия ответа Рафаэля такова:

public static string XmlEnumToString<TEnum>(this TEnum value) where TEnum : struct, IConvertible
    {
        Type enumType = typeof(TEnum);
        if (!enumType.IsEnum)
            return null;

        MemberInfo member = enumType.GetMember(value.ToString()).FirstOrDefault();
        if (member == null)
            return null;

        XmlEnumAttribute attribute = member.GetCustomAttributes(false).OfType<XmlEnumAttribute>().FirstOrDefault();
        if (attribute == null)
            return member.Name; // Fallback to the member name when there no attribute

        return attribute.Name;
    }

Наконец, я отмечу, что комментарий Rauhotz не применим к этому делу; Атрибут XmlEnumAttribute не будет присутствовать в сгенерированном коде С#, и вы просто нажмете запасной код.