我需要一个Generic函数来根据枚举的XmlEnumAttribute“Name”属性检索枚举的名称或值。例如,我定义了以下枚举:
Public Enum Currency
<XmlEnum("00")> CDN = 1
<XmlEnum("01")> USA= 2
<XmlEnum("02")> EUR= 3
<XmlEnum("03")> JPN= 4
End Enum
第一个货币枚举值为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 Name值“00”,我需要一个函数来返回值为1的Currency枚举。同样有用的是一个返回枚举名称“CDN”的函数。然后我可以简单地解析它以获得枚举值。
任何帮助将不胜感激。
答案 0 :(得分: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);
}
答案 1 :(得分: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。
答案 2 :(得分: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;
}
答案 3 :(得分:2)
这是一个从枚举中生成字典的变体,如果您需要大量使用它,可以使用它来隐藏它的反射部分。
/// <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
答案 4 :(得分:1)
我的变体是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;
}