Эта страница Microsoft помогла мне в этом.
С тех пор Enum
реализации Типа IConvertible
интерфейс, лучшая реализация должна быть чем-то вроде этого:
public T GetEnumFromString<T>(string value) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
//...
}
Это все еще разрешит передавать типов значения, реализовывая IConvertible
. Возможности редки все же.
Я изменил образец dimarzionist. Эта версия будет только работать с Перечислениями и не позволять структурам пройти.
public static T ParseEnum<T>(string enumString)
where T : struct // enum
{
if (String.IsNullOrEmpty(enumString) || !typeof(T).IsEnum)
throw new Exception("Type given must be an Enum");
try
{
return (T)Enum.Parse(typeof(T), enumString, true);
}
catch (Exception ex)
{
return default(T);
}
}
Надежда это полезно:
public static TValue ParseEnum<TValue>(string value, TValue defaultValue)
where TValue : struct // enum
{
try
{
if (String.IsNullOrEmpty(value))
return defaultValue;
return (TValue)Enum.Parse(typeof (TValue), value);
}
catch(Exception ex)
{
return defaultValue;
}
}
Можно определить статического конструктора для класса, который проверит, что тип T является перечислением, и выдайте исключение, если это не. Это - метод, упомянутый Jeffery Richter в его книжном CLR через C#.
internal sealed class GenericTypeThatRequiresAnEnum<T> {
static GenericTypeThatRequiresAnEnum() {
if (!typeof(T).IsEnum) {
throw new ArgumentException("T must be an enumerated type");
}
}
}
Тогда в методе синтаксического анализа, можно просто использовать Перечисление. Синтаксический анализ (typeof (T), вход, верный) для преобразования от строки до перечисления. Последний истинный параметр для того, чтобы игнорировать регистр входа.
Interestingly enough, apparently this is possible in other langauges (Managed C++, IL directly).
To Quote:
... Both constraints actually produce valid IL and can also be consumed by C# if written in another language (you can declare those constraints in managed C++ or in IL).
Who knows
У меня есть особое требование, когда я требовал использовать перечисление с текстом, связанным со значением перечисления. Например, когда я использую enum для указания типа ошибки, требуется описать детали ошибки.
public static class XmlEnumExtension
{
public static string ReadXmlEnumAttribute(this Enum value)
{
if (value == null) throw new ArgumentNullException("value");
var attribs = (XmlEnumAttribute[]) value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof (XmlEnumAttribute), true);
return attribs.Length > 0 ? attribs[0].Name : value.ToString();
}
public static T ParseXmlEnumAttribute<T>(this string str)
{
foreach (T item in Enum.GetValues(typeof(T)))
{
var attribs = (XmlEnumAttribute[])item.GetType().GetField(item.ToString()).GetCustomAttributes(typeof(XmlEnumAttribute), true);
if(attribs.Length > 0 && attribs[0].Name.Equals(str)) return item;
}
return (T)Enum.Parse(typeof(T), str, true);
}
}
public enum MyEnum
{
[XmlEnum("First Value")]
One,
[XmlEnum("Second Value")]
Two,
Three
}
static void Main()
{
// Parsing from XmlEnum attribute
var str = "Second Value";
var me = str.ParseXmlEnumAttribute<MyEnum>();
System.Console.WriteLine(me.ReadXmlEnumAttribute());
// Parsing without XmlEnum
str = "Three";
me = str.ParseXmlEnumAttribute<MyEnum>();
System.Console.WriteLine(me.ReadXmlEnumAttribute());
me = MyEnum.One;
System.Console.WriteLine(me.ReadXmlEnumAttribute());
}