【问题标题】:Retrieve enum value based on XmlEnumAttribute name value根据 XmlEnumAttribute 名称值检索枚举值
【发布时间】:2010-06-15 16:32:03
【问题描述】:

我需要一个通用函数来检索基于枚举的 XmlEnumAttribute“名称”属性的枚举的名称或值。例如,我定义了以下枚举:

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

第一个 Currency 枚举值为 1;枚举名称是“CDN”;并且 XMLEnumAttribute Name 属性值为“00”。

如果我有枚举值,我可以使用以下通用函数检索 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”,我需要一个函数来返回值为 1 的货币枚举。同样有用的是返回枚举名称“CDN”的函数。然后我可以简单地解析它以获得枚举值。

我们将不胜感激。

【问题讨论】:

    标签: c# vb.net reflection enums


    【解决方案1】:

    解决这个完全相同的问题的要求使我想到了这个问题和答案。当我在 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);
    }
    

    【讨论】:

    • 您可以考虑将where T : struct 添加为GetCode&lt;T&gt; 方法的约束,因为据我所知,枚举永远不会是引用类型。 (枚举以外的结构将能够通过,但恕我直言,这仍然是一个不错的小改进)
    【解决方案2】:

    我对自定义属性做了类似的事情,我使用这种方法根据属性值获取 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); 
        } 
    }  
    

    对于我使用的整个过程,请查看此帖子和答案:Extending Enums, Overkill?

    抱歉,这是在 C# 中,刚刚意识到您使用的是上面的 VB.NET。

    【讨论】:

      【解决方案3】:

      稍微修改自: 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;
      }
      

      【讨论】:

        【解决方案4】:

        这是一个从枚举生成字典的变体,允许您在需要大量使用它时潜在地缓存它的反射部分。

        /// <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
        

        【讨论】:

          【解决方案5】:

          @Dean、@Jason 和 @Camron,感谢您的解决方案。您的解决方案帮助我解决了我的问题,在给定 XmlEnumAttribute 名称的情况下,需要实际的枚举值。

          提到了我的变体here

          按照我们的一位版主的要求,我也将其包括在此处:

          实际的问题是如何获取 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;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-02
            • 1970-01-01
            相关资源
            最近更新 更多