我正在构建一个函数来扩展Enum。解析概念
允许在没有找到Enum值的情况下解析默认值
不区分大小写
所以我写下了以下内容:
public static T GetEnumFromString<T>(string value, T defaultValue) where T : Enum
{
if (string.IsNullOrEmpty(value)) return defaultValue;
foreach (T item in Enum.GetValues(typeof(T)))
{
if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
}
return defaultValue;
}
我得到一个错误约束不能是特殊类System.Enum。
很好,但是是否有一种变通方法来允许通用Enum,或者我将不得不模仿Parse函数并将类型作为属性传递,这将强制对代码进行丑陋装箱要求。
以下所有建议都非常感谢,谢谢。
已经确定(我已经离开了循环以保持大小写不敏感-我在解析XML时使用这个)
public static class EnumUtils
{
public static T ParseEnum<T>(string value, T defaultValue) where T : struct, IConvertible
{
if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");
if (string.IsNullOrEmpty(value)) return defaultValue;
foreach (T item in Enum.GetValues(typeof(T)))
{
if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
}
return defaultValue;
}
}
编辑:(2015年2月16日)Christopher currents在下面的MSIL或f#中发布了一个编译器强制类型安全的通用解决方案,非常值得一看,并获得好评。如果解决方案在页面上方出现气泡,我将删除此编辑。
编辑2:(2021年4月13日)自从c# 7.3以来,这个问题已经得到解决和支持,我已经更改了公认的答案,尽管出于学术和历史兴趣,充分阅读顶部的答案是值得的:)
现有的答案是正确的c# <=7.2。然而,有一个c#语言的功能请求(绑定到一个corefx功能请求)允许以下;
public class MyGeneric<TEnum> where TEnum : System.Enum
{ }
在撰写本文时,该特性正在语言开发会议上“讨论中”。
EDIT
根据nawfal的信息,这是在c# 7.3中引入的。
编辑2
现在在c# 7.3版本中(发布说明)
样本;
public static Dictionary<int, string> EnumNamedValues<T>()
where T : System.Enum
{
var result = new Dictionary<int, string>();
var values = Enum.GetValues(typeof(T));
foreach (int item in values)
result.Add(item, Enum.GetName(typeof(T), item));
return result;
}
C# ≥ 7.3
从c# 7.3 (Visual Studio 2017≥v15.7可用)开始,此代码现在完全有效:
public static TEnum Parse<TEnum>(string value)
where TEnum : struct, Enum
{
...
}
C# ≤ 7.2
通过滥用约束继承,可以让真正的编译器强制枚举约束。下面的代码同时指定了类和结构约束:
public abstract class EnumClassUtils<TClass>
where TClass : class
{
public static TEnum Parse<TEnum>(string value)
where TEnum : struct, TClass
{
return (TEnum) Enum.Parse(typeof(TEnum), value);
}
}
public class EnumUtils : EnumClassUtils<Enum>
{
}
用法:
EnumUtils.Parse<SomeEnum>("value");
注意:这是在c# 5.0语言规范中特别说明的:
如果类型参数S依赖于类型参数T,则:
[…它对…有效
S具有值类型约束,T具有引用类型
约束。这有效地将T限制为System类型。对象,
系统。ValueType、系统。Enum和任何接口类型。
现有的答案是正确的c# <=7.2。然而,有一个c#语言的功能请求(绑定到一个corefx功能请求)允许以下;
public class MyGeneric<TEnum> where TEnum : System.Enum
{ }
在撰写本文时,该特性正在语言开发会议上“讨论中”。
EDIT
根据nawfal的信息,这是在c# 7.3中引入的。
编辑2
现在在c# 7.3版本中(发布说明)
样本;
public static Dictionary<int, string> EnumNamedValues<T>()
where T : System.Enum
{
var result = new Dictionary<int, string>();
var values = Enum.GetValues(typeof(T));
foreach (int item in values)
result.Add(item, Enum.GetName(typeof(T), item));
return result;
}
还应该考虑到,由于使用Enum约束的c# 7.3版本是开箱即用的,无需做额外的检查和其他工作。
因此,如果你已经将项目的语言版本更改为c# 7.3,下面的代码将会完美地工作:
private static T GetEnumFromString<T>(string value, T defaultValue) where T : Enum
{
// Your code goes here...
}
如果你不知道如何将语言版本更改为c# 7.3,请参阅下面的截图:
编辑1 -需要的Visual Studio版本,并考虑ReSharper
要让Visual Studio能够识别新的语法,您至少需要版本15.7。你可以在微软的发布说明中找到,参见Visual Studio 2017 15.7发布说明。谢谢@ mohammedelshawaf指出了这个有效的问题。
请注意,在我写这篇文章时,ReSharper 2018.1还不支持c# 7.3。ReSharper激活它突出显示Enum约束作为一个错误告诉我不能使用“系统”。数组”、“系统。委托”、“系统。枚举”、“系统。ValueType', 'object'作为类型参数约束。
ReSharper建议作为一个快速修复删除'Enum'约束类型参数T的方法
然而,如果你在Tools -> Options -> ReSharper Ultimate -> General下暂时关闭ReSharper,你会发现如果你使用VS 15.7或更高版本和c# 7.3或更高版本,语法是完美的。