Convert a string to an enum in C#
用C将字符串转换为枚举值的最佳方法是什么?
我有一个包含枚举值的HTML选择标记。当页面被发布时,我想取一个值(以字符串的形式)并将其转换为枚举值。
在理想的世界里,我可以这样做:
1 | StatusEnum MyStatus = StatusEnum.Parse("Active"); |
但这不是一个有效的代码。
在.NET Core和.NET>4中,有一个通用的分析方法:
1 | Enum.TryParse("Active", out StatusEnum myStatus); |
这还包括C_7的新的内联
如果您可以访问C 7和最新的.NET,这是最好的方法。
原始答案在.NET中,它相当难看(直到4或更高版本):
1 |
我倾向于简化这一点:
1 2 3 4 |
然后我可以做:
1 | StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active"); |
注释中建议的一个选项是添加一个扩展名,这非常简单:
1 2 3 4 5 6 | public static T ToEnum<T>(this string value) { return (T) Enum.Parse(typeof(T), value, true); } StatusEnum MyStatus ="Active".ToEnum<StatusEnum>(); |
最后,如果无法分析字符串,则可能需要使用默认枚举:
1 2 3 4 5 6 7 8 9 10 | 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; } |
这就是电话:
1 | StatusEnum MyStatus ="Active".ToEnum(StatusEnum.None); |
但是,我会小心地将这样的扩展方法添加到
使用
1 2 | StatusEnum myStatus; Enum.TryParse("Active", out myStatus); |
使用C 7.0的参数类型内联可以进一步简化:
1 | Enum.TryParse("Active", out StatusEnum myStatus); |
请注意,enum.parse()的性能很糟糕,因为它是通过反射实现的。(Enum.ToString也是如此,反过来也是如此。)
如果需要在性能敏感的代码中将字符串转换为枚举,最好是在启动时创建一个
您正在查找Enum.Parse。
1 |
现在可以使用扩展方法:
1 2 3 4 | public static T ToEnum<T>(this string value, bool ignoreCase = true) { return (T) Enum.Parse(typeof (T), value, ignoreCase); } |
您可以通过以下代码调用它们(这里,
1 | FilterType filterType = type.ToEnum<FilterType>(); |
当心:
1 2 3 4 5 6 | enum Example { One = 1, Two = 2, Three = 3 } |
1 | var x = Enum.Parse("One,Two"); // x is now Three |
即使没有定义
我不想体验用户自愿或不愿意引发这种行为的后果。
另外,正如其他人所提到的,对于大型枚举(即可能值的线性数)来说,性能并不理想。
我建议如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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); } |
1 | object Enum.Parse(System.Type enumType, string value, bool ignoreCase); |
因此,如果您有一个名为mood的枚举,它将如下所示:
1 2 3 4 5 6 7 8 9 10 | enum Mood { Angry, Happy, Sad } // ... Mood m = (Mood) Enum.Parse(typeof(Mood),"Happy", true); Console.WriteLine("My mood is: {0}", m.ToString()); |
Enum.Parse是您的朋友:
1 |
您可以使用默认值扩展接受的答案,以避免出现异常:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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; } } |
然后你这样称呼它:
1 | StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None); |
我们不能假设输入是完全有效的,并使用了@keith's答案的这种变体:
1 2 3 4 5 6 7 8 9 | 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; } |
1 2 3 4 5 | // str.ToEnum<EnumType>() T static ToEnum<T>(this string str) { return (T) Enum.Parse(typeof(T), str); } |
将字符串解析为tenum,不使用try/catch,也不使用.NET 4.5中的typarse()方法
1 2 3 4 5 6 7 8 9 10 11 12 | /// <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; } |
使用胰蛋白酶的超简单代码:
1 2 3 4 5 | var value ="Active"; StatusEnum status; if (!Enum.TryParse<StatusEnum>(value, out status)) status = StatusEnum.Unknown; |
我喜欢扩展方法的解决方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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; } } } |
下面是我的测试实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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 } |
1 2 3 4 5 6 | public static T ParseEnum<T>(string value) //function declaration { return (T) Enum.Parse(typeof(T), value); } Importance imp = EnumUtil.ParseEnum<Importance>("Active"); //function call |
=======一个完整的程序==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | 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. |
我使用了类(具有解析和性能改进的强类型枚举版本)。我在Github上找到的,它也应该适用于.NET 3.5。它有一些内存开销,因为它缓冲字典。
1 | StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active"); |
blogpost是Enums——更好的语法、改进的性能和net 3.5中的Tryparse。
代码:https://github.com/damieng/damiengkit/blob/master/csharp/damieng.library/system/enumt.cs
尝试此示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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; }); } |
在这个示例中,您可以发送每个字符串,并设置您的
对于性能而言,这可能有助于:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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值的情况。所以我们走到这里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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; } |
枚举示例:
1 2 3 4 5 6 7 8 9 | public enum OracleInstanceStatus { Unknown = -1, Started = 1, Mounted = 2, Open = 3, [EnumMember(Value ="OPEN MIGRATE")] OpenMigrate = 4 } |
必须使用Enum.Parse从Enum中获取对象值,然后必须将对象值更改为特定的Enum值。可以使用convert.changeType来强制转换为枚举值。请看下面的代码段
1 2 3 |