Answers:
在.NET Core和.NET> 4中,有一个通用的解析方法:
Enum.TryParse("Active", out StatusEnum myStatus);
这还包括C#7的新内联out
变量,因此可以进行try-parse,转换为显式枚举类型并初始化并填充该myStatus
变量。
如果您可以访问C#7和最新的.NET,则这是最好的方法。
在.NET中,它相当难看(直到4或更高版本):
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
as 添加这样的扩展方法(没有名称空间控制),因为它将出现在string
它们是否拥有枚举的所有实例上(因此1234.ToString().ToEnum(StatusEnum.None)
是有效的,但毫无意义)。通常最好避免使用仅适用于非常特定的上下文的额外方法来使Microsoft的核心类混乱,除非整个开发团队对这些扩展的工作有很好的了解。
使用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
对于转换出错(值was为null
,为空或没有对应的枚举常量)引发解释性异常,它比TryParse
boolean返回值(抑制具体错误)
var result = Enum.TryParse<System.DayOfWeek>("55", out var parsedEnum);
请注意Enum.Parse()
,由于它是通过反射实现的,因此效果很糟。(的情况相同Enum.ToString
,反之亦然。)
如果您需要使用对性能敏感的代码将字符串转换为Enums,最好的选择是Dictionary<String,YourEnum>
在启动时创建一个,然后使用它来进行转换。
您正在寻找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 accepts multiple, comma-separated arguments, and combines them with binary 'or'
。意味着您可以将枚举值设置为2的幂,并且您有一种非常简单的方法来解析多个布尔标志,例如。“ UseSSL,NoRetries,Sync”。实际上,这可能就是它的设计目的。
Enum.Parse是您的朋友:
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
和方法的返回类型均为type T
。如果类型不同,则将收到一个编译时错误:“无法从'ConsoleApp1.Size'转换为'ConsoleApp1.Color'”或任何类型。
从.NET 4.5中将字符串解析为TEnum而不使用try / catch且不使用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;
}
我喜欢扩展方法解决方案。
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;
}
}
}
下面是我用测试的实现。
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
}
public static T ParseEnum<T>(string value) //function declaration
{
return (T) Enum.Parse(typeof(T), value);
}
Importance imp = EnumUtil.ParseEnum<Importance>("Active"); //function call
====================完整的程序=====================
using System;
class Program
{
enum PetType
{
None,
Cat = 1,
Dog = 2
}
static void Main()
{
// Possible user input:
string value = "Dog";
// Try to convert the string to an enum:
PetType pet = (PetType)Enum.Parse(typeof(PetType), value);
// See if the conversion succeeded:
if (pet == PetType.Dog)
{
Console.WriteLine("Equals dog.");
}
}
}
-------------
Output
Equals dog.
我使用了类(具有解析和性能改进功能的Enum的强类型版本)。我在GitHub上找到了它,它也适用于.NET 3.5。因为它缓冲字典,所以它有一些内存开销。
StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");
博客文章是Enums – NET 3.5中更好的语法,改进的性能和TryParse。
和代码:https : //github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs
为了提高性能,这可能会有所帮助:
private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
public static T ToEnum<T>(this string value, T defaultValue)
{
var t = typeof(T);
Dictionary<string, object> dic;
if (!dicEnum.ContainsKey(t))
{
dic = new Dictionary<string, object>();
dicEnum.Add(t, dic);
foreach (var en in Enum.GetValues(t))
dic.Add(en.ToString(), en);
}
else
dic = dicEnum[t];
if (!dic.ContainsKey(value))
return defaultValue;
else
return (T)dic[value];
}
我发现这里没有考虑具有EnumMember值的枚举值的情况。所以我们开始:
using System.Runtime.Serialization;
public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}
TEnum result;
var enumType = typeof(TEnum);
foreach (var enumName in Enum.GetNames(enumType))
{
var fieldInfo = enumType.GetField(enumName);
var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
if (enumMemberAttribute?.Value == value)
{
return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
}
}
return Enum.TryParse(value, true, out result) ? result : defaultValue;
}
该枚举的示例:
public enum OracleInstanceStatus
{
Unknown = -1,
Started = 1,
Mounted = 2,
Open = 3,
[EnumMember(Value = "OPEN MIGRATE")]
OpenMigrate = 4
}
试试这个例子:
public static T GetEnum<T>(string model)
{
var newModel = GetStringForEnum(model);
if (!Enum.IsDefined(typeof(T), newModel))
{
return (T)Enum.Parse(typeof(T), "None", true);
}
return (T)Enum.Parse(typeof(T), newModel.Result, true);
}
private static Task<string> GetStringForEnum(string model)
{
return Task.Run(() =>
{
Regex rgx = new Regex("[^a-zA-Z0-9 -]");
var nonAlphanumericData = rgx.Matches(model);
if (nonAlphanumericData.Count < 1)
{
return model;
}
foreach (var item in nonAlphanumericData)
{
model = model.Replace((string)item, "");
}
return model;
});
}
在此示例中,您可以发送每个字符串,然后设置Enum
。如果您Enum
有想要的数据,则将其作为Enum
类型返回。
newModel
每行,因此,如果其中包含破折号,则不会替换。另外,您不必检查字符串是否包含任何内容,可以随时调用Replace
:var newModel = model.Replace("-", "").Replace(" ", "");
不确定何时添加,但是在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;
}
如果属性名称与您要调用的名称不同(即语言差异),则可以执行以下操作:
MyType.cs
using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
[JsonConverter(typeof(StringEnumConverter))]
public enum MyType
{
[EnumMember(Value = "person")]
Person,
[EnumMember(Value = "annan_deltagare")]
OtherPerson,
[EnumMember(Value = "regel")]
Rule,
}
EnumExtensions.cs
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public static class EnumExtensions
{
public static TEnum ToEnum<TEnum>(this string value) where TEnum : Enum
{
var jsonString = $"'{value.ToLower()}'";
return JsonConvert.DeserializeObject<TEnum>(jsonString, new StringEnumConverter());
}
public static bool EqualsTo<TEnum>(this string strA, TEnum enumB) where TEnum : Enum
{
TEnum enumA;
try
{
enumA = strA.ToEnum<TEnum>();
}
catch
{
return false;
}
return enumA.Equals(enumB);
}
}
Program.cs
public class Program
{
static public void Main(String[] args)
{
var myString = "annan_deltagare";
var myType = myString.ToEnum<MyType>();
var isEqual = myString.EqualsTo(MyType.OtherPerson);
//Output: true
}
}