在C#中将一个字符串转换为枚举值的最佳方法是什么?
我有一个包含枚举值的HTML选择标签。当页面被提交时,我希望获取这个值(它将以字符串形式存在)并将其转换为相应的枚举值。
在理想的情况下,我可以这样做:
StatusEnum MyStatus = StatusEnum.Parse("Active");
但那不是有效的代码。
在C#中将一个字符串转换为枚举值的最佳方法是什么?
我有一个包含枚举值的HTML选择标签。当页面被提交时,我希望获取这个值(它将以字符串形式存在)并将其转换为相应的枚举值。
在理想的情况下,我可以这样做:
StatusEnum MyStatus = StatusEnum.Parse("Active");
但那不是有效的代码。
Enum.TryParse("Active", out StatusEnum myStatus);
out
变量,因此它执行try-parse、转换为显式枚举类型并初始化+填充myStatus
变量。StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);
我倾向于这样简化:
public static T ParseEnum<T>(string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");
评论中提出的一个建议是添加一个扩展程序,这很简单:
public static T ToEnum<T>(this string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();
public static T ToEnum<T>(this string value, T defaultValue)
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}
T result;
return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}
StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);
然而,我建议小心将这样的扩展方法添加到string
中,因为(没有命名空间控制)它会出现在所有string
实例上,无论它们是否持有枚举(因此1234.ToString().ToEnum(StatusEnum.None)
是有效但无意义的)。除非您的整个开发团队非常了解这些扩展的功能,否则最好避免在非常特定的上下文中向Microsoft的核心类添加额外的方法。
Use Enum.TryParse<T>(String, T)
(≥ .NET 4.0):
StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);
使用C# 7.0的参数类型内联可以进一步简化:
Enum.TryParse("Active", out StatusEnum myStatus);
Parse
会抛出解释性异常,说明转换出现了什么问题(值为 null
、空或没有对应的枚举常量),这比 TryParse
的布尔返回值要好得多(后者会压制具体错误)。 - yairvar result = Enum.TryParse("55", out var parsedEnum);
- Mass Dot Net&& Enum.IsDefined(typeof(System.DayOfWeek), parsedEnum)
来确保解析的枚举实际存在。 - WalterEnum.Parse()
的性能并不理想,因为它是通过反射实现的(同样适用于相反的Enum.ToString()
)。
如果你需要在对性能敏感的代码中将字符串转换为枚举,最好在启动时创建一个Dictionary<String,YourEnum>
,并使用它来进行转换。
MyEnum myEnum = Enum.Parse<MyEnum>("Seven");
它产生了以下结果:
平均值:33.19 ns
错误:0.469 ns
标准差:0.392 ns - FanbladeEnum.TryParse<MyEnum>(Input, out MyEnum result);
。这并不是“糟糕的”。 - Fanblade你正在寻找Enum.Parse。
SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
现在你可以使用扩展方法:
public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
return (T) Enum.Parse(typeof (T), value, ignoreCase);
}
你可以通过以下代码调用它们(这里,FilterType
是一个枚举类型):
FilterType filterType = type.ToEnum<FilterType>();
注意:
enum Example
{
One = 1,
Two = 2,
Three = 3
}
Enum.(Try)Parse()
接受多个逗号分隔的参数,并使用二进制“或”|
组合它们。你无法禁用它,而且在我看来你几乎永远不想这样做。var x = Enum.Parse("One,Two"); // x is now Three
Three
未定义,x
仍将获得int值3
。这甚至更糟糕:Enum.Parse()可以给您一个甚至未为枚举定义的值! public static bool TryParse<T>(string value, out T result)
where T : struct
{
var cacheKey = "Enum_" + typeof(T).FullName;
// [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
// [Implementation off-topic.]
var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);
return enumDictionary.TryGetValue(value.Trim(), out result);
}
private static Dictionary<string, T> CreateEnumDictionary<T>()
{
return Enum.GetValues(typeof(T))
.Cast<T>()
.ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
}
Enum.(Try)Parse
接受多个逗号分隔参数,并使用二进制“或”组合它们是非常有用的。这意味着您可以将枚举值设置为2的幂,并且您有一种非常简单的方式来解析多个布尔标志,例如“UseSSL,NoRetries,Sync”。实际上,这可能就是其设计目的。 - pcdev在某个时候,解析的通用版本被添加了。对我而言,这更可取,因为我不需要“尝试”解析,同时我也希望结果是内联的,而不是生成一个输出变量。
ColorEnum color = Enum.Parse<ColorEnum>("blue");
ColorEnum color = (ColorEnum)Enum.Parse(typeof(ColorEnum), "blue");
。 - WSCobject Enum.Parse(System.Type enumType, string value, bool ignoreCase);
所以如果你有一个名为mood的枚举,它会长成这样:
enum Mood
{
Angry,
Happy,
Sad
}
// ...
Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
Console.WriteLine("My mood is: {0}", m.ToString());
StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
您可以通过设置默认值来扩展接受的答案以避免异常:
public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
try
{
T enumValue;
if (!Enum.TryParse(value, true, out enumValue))
{
return defaultValue;
}
return enumValue;
}
catch (Exception)
{
return defaultValue;
}
}
然后你可以这样调用:
StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
如果默认值不是枚举,则 Enum.TryParse 将失败并抛出异常,该异常被捕获。
多年来,在我们的代码中广泛使用此函数的情况下,也许添加这个操作会带来性能成本的信息是有益的!
defaultValue
和方法返回类型都是 T
类型。如果类型不同,则会收到编译时错误:“无法从 'ConsoleApp1.Size' 转换为 'ConsoleApp1.Color'”或其他类型。 - andleer