通过发送XmlEnumAttribute c#获取枚举的元素? [英] Get element of an enum by sending XmlEnumAttribute c#?

查看:139
本文介绍了通过发送XmlEnumAttribute c#获取枚举的元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通常不必问问题,因为大多数时候我都可以在互联网上找到所需的东西,但是现在我还没有找到一种方法来解决这个问题:

I normaly dont have to ask questions because most of the times I find what I need on internet, but now i haven´t find a way to get this:

想象一下,我喜欢这个枚举中的50000个枚举元素:

Imagine that I have like 50000 enum elements in this enum:

public enum myEnum
{
   [System.Xml.Serialization.XmlEnumAttribute("01010101")]
   Item01010101,
   [System.Xml.Serialization.XmlEnumAttribute("10101500")]
   Item10101500
}

我想要做的是通过传递元素的XmlEnumAttribute的字符串值来获得元素值,例如

what i am trying to do is to get the element value by passing the string value for XmlEnumAttribute of the element, for example

object.ItsEnumValue = getEnumElement("01010101");

// Function which will return the element of the enum.
public myEnum getEnumElement(string xmlAttributeValue)
{
    // The function should return the enum element, not using a switch statement
    return myEnum.Item01010101;
}

没有switch语句,有没有办法做到这一点?
我希望您能帮助我,谢谢。

Is there a way to do this without a switch statement? I hope you can help me, thanks.

推荐答案

您有几种方法可以解决此问题。

You have a couple methods to solve this problem.

首先,您可以使用反射通过 typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static)遍历所有枚举值

类似于此此答案中的操作方式:

Firstly, you can use reflection to cycle through all the enum values using typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static) similarly to how it is done in this this answer:

public static partial class XmlEnumExtensions
{
    public static TEnum FromReflectedXmlValue<TEnum>(this string xml) where TEnum : struct, IConvertible, IFormattable
    {
        // Adapted from https://stackoverflow.com/questions/35294530/c-sharp-getting-all-enums-value-by-attribute
        var obj = (from field in typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static)
                   from attr in field.GetCustomAttributes<XmlEnumAttribute>()
                   where attr != null && attr.Name == xml
                   select field.GetValue(null)).SingleOrDefault();
        if (obj != null)
            return (TEnum)obj;

        // OK, maybe there is no XmlEnumAttribute override so match on the name.
        return (TEnum)Enum.Parse(typeof(TEnum), xml, false);
    }
}

然后使用它:

obj.ItsEnumValue = "01010101".FromReflectedXmlValue<myEnum>();

但是,当 [Flags] 属性已应用。例如,给定以下枚举:

However, this will not work when the [Flags] attribute is applied. For instance, given the following enum:

[Flags]
public enum myFlagsEnum
{
    [System.Xml.Serialization.XmlEnumAttribute("Flag0")]
    Zero = (1 << 0),
    [System.Xml.Serialization.XmlEnumAttribute("Flag1")]
    One = (1 << 1),
}

从值 myFlagsEnum.Zero | myFlagsEnum.One XmlSerializer 将生成以下组合字符串,不能仅通过反射找到: Flag0 Flag1 。将多个 XmlEnumAttribute 属性应用于给定的枚举值,或者仅某些枚举值具有 XmlEnumAttribute

From the value myFlagsEnum.Zero | myFlagsEnum.One, XmlSerializer will generate the following combined string, which cannot be found purely by reflection: Flag0 Flag1. Nor is it clear what should happen when multiple XmlEnumAttribute attributes are applied to a given enum value, or only some of the enum values have XmlEnumAttribute applied.

要处理包括上述内容在内的所有可能的边缘情况,我建议直接使用以下方法直接对XML进行反序列化第二种方法:

To handle all possible edge cases including the above, I would suggest simply deserializing the XML directly, using the following second method:

public static partial class XmlExtensions
{
    static XmlExtensions()
    {
        noStandardNamespaces = new XmlSerializerNamespaces();
        noStandardNamespaces.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd attributes.
    }

    readonly static XmlSerializerNamespaces noStandardNamespaces;
    internal const string RootNamespace = "XmlExtensions";
    internal const string RootName = "Root";

    public static TEnum FromXmlValue<TEnum>(this string xml) where TEnum : struct, IConvertible, IFormattable
    {
        var element = new XElement(XName.Get(RootName, RootNamespace), xml);
        return element.Deserialize<XmlExtensionsEnumWrapper<TEnum>>().Value;
    }

    public static T Deserialize<T>(this XContainer element, XmlSerializer serializer = null)
    {
        using (var reader = element.CreateReader())
        {
            object result = (serializer ?? new XmlSerializer(typeof(T))).Deserialize(reader);
            if (result is T)
                return (T)result;
        }
        return default(T);
    }

    public static string ToXmlValue<TEnum>(this TEnum value) where TEnum : struct, IConvertible, IFormattable
    {
        var root = new XmlExtensionsEnumWrapper<TEnum> { Value = value };
        return root.SerializeToXElement().Value;
    }

    public static XElement SerializeToXElement<T>(this T obj)
    {
        return obj.SerializeToXElement(null, noStandardNamespaces); // Disable the xmlns:xsi and xmlns:xsd attributes by default.
    }

    public static XElement SerializeToXElement<T>(this T obj, XmlSerializer serializer, XmlSerializerNamespaces ns)
    {
        var doc = new XDocument();
        using (var writer = doc.CreateWriter())
            (serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns);
        var element = doc.Root;
        if (element != null)
            element.Remove();
        return element;
    }
}

[XmlRoot(XmlExtensions.RootName, Namespace = XmlExtensions.RootNamespace)]
[XmlType(IncludeInSchema = false)]
public class XmlExtensionsEnumWrapper<TEnum>
{
    [XmlText]
    public TEnum Value { get; set; }
}

这样可以保证与 XmlSerializer 在所有情况下-实际使用它。然后类似地执行以下操作:

This guarantees compatibility with XmlSerializer in all cases - by actually using it. Then similarly do:

obj.ItsEnumValue = "01010101".FromXmlValue<myEnum>();

示例小提琴

这篇关于通过发送XmlEnumAttribute c#获取枚举的元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆