2010-06-15 13 views
17

Potrzebuję funkcji ogólnej, aby pobrać nazwę lub wartość wyliczenia na podstawie właściwości "Nazwa" obiektu wyliczeniowego XmlEnumAttribute. Na przykład mam następujące zdefiniowane wyrażenie:Odzyskaj wartość wyliczenia na podstawie wartości nazwy XmlEnumAttribute

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

Pierwsza wartość wyliczenia waluty to 1; nazwa wyliczeniowa to "CDN"; a wartość właściwości Nazwa XMLEnumAttribute to "00".

Jeśli mam wartość enum, mogę odzyskać „Nazwa” wartość XmlEnumAttribute stosując następującą funkcję Generic:

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 

Więc stosując powyższą funkcję, można określić typ enum walut, przekazać wartość 1, a wartością zwracaną będzie "00".

Potrzebuję funkcji do wykonania, jeśli jest odwrotnie. Jeśli mam wartość XmlEnumAttribute o wartości "00", potrzebuję funkcji zwracania wyliczenia waluty o wartości 1. Tak samo przydatna byłaby funkcja zwracająca nazwę wyliczeniową "CDN". Mógłbym wtedy po prostu przeanalizować to, aby uzyskać wartość wyliczeniową.

Każda pomoc zostanie doceniona.

Odpowiedz

17

Wymóg rozwiązania tego samego problemu doprowadził mnie do tego pytania i odpowiedzi. W miarę rozwoju w VB.NET przerobiłem rozwiązanie CkH na VB i zmodyfikowałem je tak, aby korzystać z funkcji 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# Version:

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

Dziękuję za odpowiedź. – Dean

+0

Możesz rozważyć dodanie 'where T: struct' jako ograniczenia metody' GetCode ', ponieważ wyliczenie nigdy nie będzie typem referencyjnym, o ile moja wiedza idzie.(Struktury inne niż wyliczenia będą w stanie przejść, ale nadal jest to mała poprawa IMHO) –

7

Robię coś podobnego z atrybutami niestandardowymi i używam tej metody, aby uzyskać wartość EnumValue w oparciu o wartość atrybutu. GetStringValue to moja metoda niestandardowa, podobna do powyższego przykładu.

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

Dla całego procesu używam sprawdzić ten post i odpowiedź: Extending Enums, Overkill?

Niestety to jest w C#, po prostu realizowane były przy użyciu VB.NET powyżej.

+0

Dzięki za odpowiedź. – Dean

1

@Dean, @Jason i @Camron, dziękuję za swoimi rozwiązaniami. Twoje rozwiązania pomogły mi rozwiązać mój problem, gdzie, biorąc pod uwagę nazwę XmlEnumAttribute, potrzebna była rzeczywista wartość wyliczeniowa.

Mój wariant jest wymieniony here.

3

lekko modyfikowany: 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

Oto odmiana, która generuje słownik z wyliczenia, co pozwala na potencjalnie buforować część odbicia nim powinna trzeba użyć bardzo dużo.

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

Wykorzystanie:

var map = GetEnumMap<Currency>(); 
return map["02"]; // returns Currency.EUR 
Powiązane problemy