2010-06-15 74 views
17

我需要一個通用函數來基於枚舉的XmlEnumAttribute「Name」屬性檢索枚舉的名稱或值。例如我有以下枚舉定義:基於XmlEnumAttribute名稱值檢索枚舉值

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

第一個貨幣枚舉值是1;枚舉名稱是「CDN」;並且XMLEnumAttribute名稱屬性值是「00」。

如果我有枚舉值,我可以使用下面的通用函數檢索XmlEnumAttribute「名稱」值:

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 

因此,使用上述功能,我可以指定貨幣枚舉類型,傳值爲1,返回值爲「00」。

我需要的是一個函數執行,如果相反。如果我有XmlEnumAttribute名稱值「00」,我需要一個函數返回一個值爲1的貨幣枚舉。正如有用的將是一個函數,將返回枚舉名稱「CDN」。然後我可以簡單地解析這個來獲得枚舉值。

任何援助將不勝感激。

回答

17

解決這個完全相同的問題的要求使我對這個問題和答案。當我在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); 
} 
+0

感謝您的回覆。 – Dean 2010-07-05 17:03:46

+0

你可以考慮在'GetCode '方法中添加'where T:struct'作爲約束,因爲根據我的知識,枚舉永遠不會是引用類型。(枚舉以外的結構將能夠通過,但它仍然是一個不錯的小改進恕我直言) – 2017-10-11 09:15:56

7

我做了類似自定義屬性的東西,我使用這種方法來獲取基於屬性值的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上面你。

+0

感謝您的答覆。 – Dean 2010-07-05 17:04:03

1

@Dean,@Jason和@Camron,感謝您的解決方案。您的解決方案幫助我解決了問題,在給定XmlEnumAttribute名稱的情況下,需要實際的枚舉值。

我的變體被提及here

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

下面是從枚舉生成字典,讓您的潛在緩存它的反射部分如果你需要使用它了很多的變化。

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