在C#中将字符串转换为枚举值的最佳方法是什么?
我有一个包含枚举值的HTML选择标记.发布页面时,我想获取值(将以字符串的形式)并将其转换为枚举值.
在一个理想的世界里,我可以这样做:
StatusEnum MyStatus = StatusEnum.Parse("Active");
Run Code Online (Sandbox Code Playgroud)
但那不是有效的代码.
Kei*_*ith 1362
在.NET Core和.NET> 4中,有一个通用的解析方法:
Enum.TryParse("Active", out StatusEnum myStatus);
Run Code Online (Sandbox Code Playgroud)
这还包括C#7的新内联out
变量,因此这将执行try-parse,转换为显式枚举类型并初始化+填充myStatus
变量.
如果您可以访问C#7和最新的.NET,这是最好的方法.
在.NET中它相当丑陋(直到4或以上):
StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);
Run Code Online (Sandbox Code Playgroud)
我倾向于简化这个:
public static T ParseEnum<T>(string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
Run Code Online (Sandbox Code Playgroud)
然后我可以这样做:
StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");
Run Code Online (Sandbox Code Playgroud)
评论中建议的一个选项是添加一个扩展,这很简单:
public static T ToEnum<T>(this string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();
Run Code Online (Sandbox Code Playgroud)
最后,如果无法解析字符串,您可能希望使用默认枚举:
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;
}
Run Code Online (Sandbox Code Playgroud)
这使得这个电话:
StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);
Run Code Online (Sandbox Code Playgroud)
但是,我会小心地将这样的扩展方法添加到string
(没有命名空间控制)它将出现在所有实例上,string
无论它们是否包含枚举(因此1234.ToString().ToEnum(StatusEnum.None)
有效但无意义).通常最好避免使用仅在非常特定的上下文中应用的额外方法来混淆Microsoft的核心类,除非您的整个开发团队非常了解这些扩展的作用.
Erw*_*yer 306
使用Enum.TryParse<T>(String, T)
(≥.NET4.0):
StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);
Run Code Online (Sandbox Code Playgroud)
使用C#7.0的参数类型内联可以进一步简化:
Enum.TryParse("Active", out StatusEnum myStatus);
Run Code Online (Sandbox Code Playgroud)
McK*_*eG1 186
请注意,Enum.Parse()的性能很糟糕,因为它是通过反射实现的.(对于Enum.ToString也是如此,这是另一种方式.)
如果您需要在性能敏感的代码中将字符串转换为枚举,最好的办法是Enum.Parse()
在启动时创建并使用它来进行转换.
Dav*_*ney 92
你正在寻找Enum.Parse.
SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
Run Code Online (Sandbox Code Playgroud)
Jor*_*dan 31
在某个时候,添加了 Parse 的通用版本。对我来说,这是更可取的,因为我不需要“尝试”解析,而且我还希望结果内联而不生成输出变量。
ColorEnum color = Enum.Parse<ColorEnum>("blue");
Run Code Online (Sandbox Code Playgroud)
Foy*_*rim 29
您现在可以使用扩展方法:
public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
return (T) Enum.Parse(typeof (T), value, ignoreCase);
}
Run Code Online (Sandbox Code Playgroud)
您可以通过以下代码调用它们(这里FilterType
是一个枚举类型):
FilterType filterType = type.ToEnum<FilterType>();
Run Code Online (Sandbox Code Playgroud)
bre*_*dan 19
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);
Run Code Online (Sandbox Code Playgroud)
所以,如果你有一个名为heart的枚举,它将如下所示:
enum Mood
{
Angry,
Happy,
Sad
}
// ...
Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
Console.WriteLine("My mood is: {0}", m.ToString());
Run Code Online (Sandbox Code Playgroud)
Tim*_*imo 18
谨防:
enum Example
{
One = 1,
Two = 2,
Three = 3
}
Run Code Online (Sandbox Code Playgroud)
Enum.(Try)Parse()
接受多个逗号分隔的参数,并将它们与二进制'或'组合|
.你不能禁用它,在我看来你几乎从不想要它.
var x = Enum.Parse("One,Two"); // x is now Three
Run Code Online (Sandbox Code Playgroud)
即使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);
}
Run Code Online (Sandbox Code Playgroud)
tag*_*s2k 16
Enum.Parse是你的朋友:
StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
Run Code Online (Sandbox Code Playgroud)
Blo*_*mer 15
这里的大多数答案都要求您每次调用扩展方法时始终传递枚举的默认值。如果您不想采用这种方法,可以像下面这样实现:
public static TEnum ToEnum<TEnum>(this string value) where TEnum : struct
{
if (string.IsNullOrWhiteSpace(value))
return default(TEnum);
return Enum.TryParse(value, true, out TEnum result) ? result : default(TEnum);
}
Run Code Online (Sandbox Code Playgroud)
使用默认文字(从 C# 7.1 开始)
public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue = default) where TEnum : struct
{
if (string.IsNullOrWhiteSpace(value))
return defaultValue ;
return Enum.TryParse(value, true, out TEnum result) ? result : defaultValue ;
}
Run Code Online (Sandbox Code Playgroud)
更好的是:
public static TEnum ToEnum<TEnum>(this string value) where TEnum : struct
{
if (string.IsNullOrWhiteSpace(value))
return default;
return Enum.TryParse(value, true, out TEnum result) ? result : default;
}
Run Code Online (Sandbox Code Playgroud)
Nel*_*lly 11
您可以使用默认值扩展接受的答案以避免例外:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你称之为:
StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
Run Code Online (Sandbox Code Playgroud)
我们无法假设完全有效的输入,并且随着@ Keith的回答变化:
public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
TEnum tmp;
if (!Enum.TryParse<TEnum>(value, true, out tmp))
{
tmp = new TEnum();
}
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str)
{
return (T) Enum.Parse(typeof(T), str);
}
Run Code Online (Sandbox Code Playgroud)
将字符串解析为TEnum,不使用try/catch,也不使用.NET 4.5中的TryParse()方法
/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
return false;
enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
return true;
}
Run Code Online (Sandbox Code Playgroud)
我喜欢扩展方法解决方案..
namespace System
{
public static class StringExtensions
{
public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
{
T result;
var isEnum = Enum.TryParse(value, out result);
output = isEnum ? result : default(T);
return isEnum;
}
}
}
Run Code Online (Sandbox Code Playgroud)
下面是我的测试实现。
using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;
private enum Countries
{
NorthAmerica,
Europe,
Rusia,
Brasil,
China,
Asia,
Australia
}
[TestMethod]
public void StringExtensions_On_TryParseAsEnum()
{
var countryName = "Rusia";
Countries country;
var isCountry = countryName.TryParseAsEnum(out country);
WriteLine(country);
IsTrue(isCountry);
AreEqual(Countries.Rusia, country);
countryName = "Don't exist";
isCountry = countryName.TryParseAsEnum(out country);
WriteLine(country);
IsFalse(isCountry);
AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
}
Run Code Online (Sandbox Code Playgroud)
使用 TryParse 的超级简单代码:
var value = "Active";
StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
status = StatusEnum.Unknown;
Run Code Online (Sandbox Code Playgroud)
不确定这是什么时候添加的,但在 Enum 类上现在有一个
Parse<TEnum>(stringValue)
像这样使用有问题的例子:
var MyStatus = Enum.Parse<StatusEnum >("Active")
或忽略大小写:
var MyStatus = Enum.Parse<StatusEnum >("active", true)
这是它使用的反编译方法:
[NullableContext(0)]
public static TEnum Parse<TEnum>([Nullable(1)] string value) where TEnum : struct
{
return Enum.Parse<TEnum>(value, false);
}
[NullableContext(0)]
public static TEnum Parse<TEnum>([Nullable(1)] string value, bool ignoreCase) where TEnum : struct
{
TEnum result;
Enum.TryParse<TEnum>(value, ignoreCase, true, out result);
return result;
}
Run Code Online (Sandbox Code Playgroud)