Get element of an enum by sending XmlEnumAttribute c#?

后端 未结 2 1356
感动是毒
感动是毒 2021-01-25 02:38

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:

Imagine that I have like 50000

相关标签:
2条回答
  • 2021-01-25 03:26

    You have a couple methods to solve this problem.

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

    Then use it like:

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

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

    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.

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

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

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

    Sample fiddle.

    0 讨论(0)
  • 2021-01-25 03:29

    Thanks dbc the first method works perfectly for what i need to do, :) i really appreciate your help, i created this class:

    public static partial class XmlEnumExtensions
    {
        public static Nullable<TEnum> FromReflectedXmlValue<TEnum>(this string xml) where TEnum : struct, IConvertible, IFormattable
        {
            try
            {
                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);
    
            }
            catch (ArgumentException ex)
            {
                throw new ApplicationException("Error: " + ex.Message);
            }
        }
    }
    

    And then I just call the method FromReflectedXmlValue like this:

    var obj4 = XmlEnumExtensions.FromReflectedXmlValue<myEnum>("theXmlAtributeValue");
    
    0 讨论(0)
提交回复
热议问题