我正在构建一个扩展 Enum.Parse
概念的函数
-
允许在未找到枚举值的情况下解析默认值
-
不区分大小写
所以我写了以下内容:
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
.
不够公平,但有一种变通方法,让一个通用枚举,还是我将不得不模仿 Parse
功能,并通过一个类型的属性,这迫使丑拳击要求你的代码 .
EDIT 以下所有建议都非常感谢,谢谢 .
已经解决了(我已经离开循环以保持不区分大小写 - 我在解析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;
}
}
EDIT: (2015年2月16日)Julien Lebosquain最近发布了下面的a compiler enforced type-safe generic solution in MSIL or F#,这是非常值得一看的,也是一个upvote . 如果解决方案在页面上向上冒泡,我将删除此编辑 .
20 回答
我通过dimarzionist修改了样本 . 此版本仅适用于Enums,不允许结构通过 .
C#≥7.3
从C#7.3开始(Visual Studio2017≥v15.7提供),此代码现在完全有效:
C#≤7.2
您可以通过滥用约束继承来获得真正的编译器强制枚举约束 . 以下代码同时指定了
class
和struct
约束:用法:
注意:这在C#5.0语言规范中有明确说明:
我已将Vivek的解决方案封装到您可以重用的实用程序类中 . 请注意,您仍应在类型上定义类型约束“where T:struct,IConvertible” .
我确实有特定的要求,我需要使用enum与enum值相关联的文本 . 例如,当我使用enum指定错误类型时,它需要描述错误详细信息 .
希望这有用:
在java中,你会用...
很简单,那个 .
这是我的看法 . 结合答案和MSDN
MSDN Source
您可以为类定义静态构造函数,该构造函数将检查类型T是否为枚举,如果不是则抛出异常 . 这是Jeffery Richter在他的书CLR中通过C#提到的方法 .
然后在parse方法中,您可以使用Enum.Parse(typeof(T),input,true)将字符串转换为枚举 . 最后一个真实参数用于忽略输入的大小写 .
我创建了一个扩展方法
to get integer value from enum
看看方法实现这是用法
从C#<= 7.2开始,现有答案都是正确的 . 但是,有一个C#语言feature request(与corefx功能请求绑定)允许以下内容;
在撰写本文时,该功能在语言发展 Session 上进行了“讨论” .
EDIT
根据nawfal的信息,这是在C#7.3中引入的 .
还应该考虑到,因为使用Enum约束的C#7.3的发布支持开箱即用而无需进行额外的检查和填充 .
因此,如果您已将项目的语言版本更改为C#7.3,则以下代码将完美地运行:
如果您知道如何将语言版本更改为C#7.3,请参阅以下屏幕截图:
EDIT 1 - Required Visual Studio Version and considering ReSharper
要使Visual Studio能够识别至少需要15.7版本的新语法 . 您可以找到Microsoft发行说明中提到的内容,请参阅Visual Studio 2017 15.7 Release Notes . 感谢@MohamedElshawaf指出这个有效的问题 .
请注意,在我的案例中,ReSharper 2018.1在编写此EDIT时尚不支持C#7.3 . 有ReSharper的激活它突出的枚举约束为一个错误,告诉我不能用'System.Array','System.Delegate','System.Enum','System.ValueType','object'类型参数约束 . ReSharper建议快速修复删除方法类型参数T的'Enum'约束
但是,如果您在工具暂时关闭ReSharper的 - >选项 - > ReSharper的终极 - >常规,你会看到,语法是完全没有考虑到你使用VS 15.7或更高版本和C#7.3或更高版本 .
有趣的是,显然这是possible in other langauges(Managed C,IL直接) .
报价:
谁知道
我喜欢使用IL的Christopher Currens解决方案,但对于那些不想处理将MSIL包含在构建过程中的棘手业务的人,我在C#中编写了类似的功能 .
请注意,虽然您不能使用像
where T : Enum
这样的通用限制,因为Enum是特殊类型 . 因此,我必须检查给定的泛型类型是否真的是枚举 .我的功能是:
如果以后可以直接使用直接投射,我猜你可以在你的方法中使用
System.Enum
基类,只要有必要 . 您只需要仔细更换类型参数 . 所以方法实现如下:然后你可以使用它喜欢:
我总是喜欢这个(你可以适当修改):
由于
Enum
Type实现了IConvertible
接口,更好的实现应该是这样的:这仍然允许传递实现
IConvertible
的值类型 . 但机会很少 .我试着改进一下代码:
Edit
Julien Lebosquain现在已经很好地回答了这个问题 . 我还想用
ignoreCase
,defaultValue
和可选参数扩展他的答案,同时添加TryParse
和ParseOrDefault
.用法示例:
Old
通过使用注释和'new'开发我对Vivek's answer的旧改进:
使用
TEnum
以明确用户为附加约束检查添加更多接口约束
让TryParse使用现有参数处理
ignoreCase
(在VS2010 / .Net 4中引入)可选择使用泛型default value(在VS2005 / .Net 2中引入)
使用optional arguments(在VS2010 / .Net 4中引入),默认值为
defaultValue
和ignoreCase
导致:
C#7.3最终支持此功能!
以下代码段(来自the dotnet samples)演示了它的用途:
请务必在C#项目中将语言版本设置为7.3版 .
原始答案如下:
我在C#(或VB.NET,但向下滚动F#)中是不可能的,但在MSIL中是可能的 . 我写了这个小东西
如果它是有效的C#,它会生成 would 看起来像这样的函数:
然后使用以下C#代码:
不幸的是,这意味着将这部分代码用MSIL而不是C#编写,唯一的好处是你能够通过
System.Enum
约束这个方法 . 它意味着你必须以这种方式部署它 .删除行
.assembly MyThing{}
并按如下方式调用ilasm:你得到一个netmodule而不是一个程序集 .
不幸的是,VS2010(显然更早)不支持添加netmodule引用,这意味着你需要重新调试 . 将它们作为程序集的一部分添加的唯一方法是使用
/addmodule:{files}
命令行参数自行运行csc.exe . 它在MSBuild脚本中不会太痛苦 . 当然,如果你是勇敢或愚蠢的,你可以每次手动运行csc . 当多个程序集需要访问它时,它肯定会变得更加复杂 .所以,它可以在.Net中完成 . 是否值得付出额外的努力?嗯,好吧,我想我会让你决定那一个 .
F#解决方案作为替代方案
额外信用:事实证明除了MSIL之外,至少还有一种其他.NET语言可以对
enum
进行通用限制:F# .这个更容易维护,因为它是一个完全支持Visual Studio IDE的着名语言,但您仍然需要在解决方案中使用单独的项目 . 但是,它自然会产生相当不同的IL(代码非常不同),它依赖于
FSharp.Core
库,就像任何其他外部库一样,它需要成为您的发行版的一部分 .以下是如何使用它(基本上与MSIL解决方案相同),并显示它在其他同义结构上正确失败:
如之前的其他答案所述;虽然这不能用源代码表示,但它实际上可以在IL Level上完成 . @Christopher Currens answer展示了IL如何做到这一点 .
使用Fody的加载项ExtraConstraints.Fody,有一种非常简单的方法,完成构建工具,以实现这一目标 . 只需将他们的nuget包(
Fody
,ExtraConstraints.Fody
)添加到您的项目中并添加如下约束(摘自ExtraConstraints自述文件):并且Fody将为存在的约束添加必要的IL . 另请注意约束代表的附加功能:
关于Enums,您可能还想注意非常有趣的Enums.NET .