Enum.Parse()或Switch

要将字符串转换为枚举,以下哪种方式更好?

  1. 这段代码:

    colorEnum color = (colorEnum)Enum.Parse(typeof(colorEnum), "Green"); 
  2. 或这个:

     string colorString = ... colorEnum color; switch (colorString) { case "Green": color = colorEnum.Green; break; case "Red": color = colorEnum.Red; break; case "Orange": color = colorEnum.Orange; break; .... } 

您应该使用Enum.TryParse,如果失败,您可以正确处理错误。

样品:

  ColorsEnum colorValue; if (Enum.TryParse(colorString, out colorValue)) if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(",")) Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString()); else Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString); else Console.WriteLine("{0} is not a member of the Colors enumeration.", colorString); 

(警告:包含我自己的开源库的插件……)

就个人而言,我会使用Unconstrained Melody ,最终会得到更清晰,更安全的代码:

 ColorEnum color = Enums.ParseName(text); 

如果您怀疑它可能无效,可以使用TryParseName 。 显然这需要一个额外的库,但希望你会发现其他有用的东西:)

.NET 4中的Enum.TryParse比其他内置选项更好,但是:

  • 你不会在编译时捕获非枚举类型,例如Enum.TryParse(...)仍将编译; 无约束的旋律真的只允许枚举类型
  • Enum.TryParse也将解析“1”(或转换为字符串时的数值) – 如果你真的只想要名字,我认为最好只接受名字

我肯定不会打开字符串值 – 这意味着如果重命名枚举值,你必须记住重命名案例值。

那么Enum.TryParse呢?

 string myColorStr = "red"; colorEnum myColor; if(!Enum.TryParse(myColorStr, true, out myColor)) { throw new InvalidOperationException("Unknown color " + myColorStr); } 

简单来说就是可读性和可维护性。 如果你扩展枚举,你不需要做额外的工作,有了2,你必须在switch语句中添加更多的情况

因为你添加了标签’performance’,所以我会选择开关。
是的,当您重命名/添加/删除枚举中的任何内容时,您将不得不更改案例。 那太糟糕了。 Enum.Parse / TryParse的任何变体都使用了很多奇怪的代码和一些reflection,只需看一下ILSpy等函数。 然后还有接受“-12354”的问题,甚至是逗号分隔的有效名称列表(导致所有这些名称一起进行OR运算),即使枚举没有[Flags]属性也是如此。

作为替代方案,您可以创建一个将枚举名称转换为值的字典。 它实际上应该比开关更快,因为字符串上的开关也会通过字典但您保存实际的开关部分。

显然,这两种方式都比enum.parse和变体需要更多的维护; 是否值得,取决于 ,因为在我们所有人中,只有你对项目有足够的了解才能使性能/编码时间权衡。

1)好多了。 这是更清洁的代码。 你在一行中做了多少2)。 此外,它不容易出错。 当你向colorEnum添加另一个项目时,你需要记住扩展2)wheras 1)才能正常工作。

您可能还需要在Enum.Parse上进行一些error handling。

除了两个不同的代码片段没有做同样的事情,我会使用这个:

 colorEnum color; if (!colorEnum.TryParse(colorString, true, out color) color = colorEnum.Green; // Or whatever default value you wish to have. 

如果您没有.NET 4.0,那么我会做这样的事情:

 public static TEnum ToEnum(this string strEnumValue, TEnum defaultValue) { if (!Enum.IsDefined(typeof(TEnum), strEnumValue)) return defaultValue; return (TEnum)Enum.Parse(typeof(TEnum), strEnumValue); } 

这是string的扩展方法 。

就个人而言,虽然我对非性能场景的Enum.Parse解决方案完全没问题(阅读:偶尔运行此function一次……并且有很多这样的场景可以肯定),我无法满足于可能涉及一些reflection类型方法,当需要在一个循环中执行此函数时,可以同时执行数百/千行以上的枚举值。 GACK!

所以以下是一个解决方案,可以获得两个世界中最好的一些。

只需在启动时检索枚举的所有值,或者什么不是,只要它最适合您(下面是一种方法),然后用它们构造一个词典。

  private static Dictionary colorDictionary; public static Dictionary ColorDictionary { get { if (colorDictionary== null) { colorDictionary = new Dictionary(); var all = Enum.GetValues(typeof(Color)).OfType(); foreach (var val in all) dict.Add(val.ToString(), val); } return colorDictionary; } } 

我发现开关变体很糟糕,因为每次更改枚举时都必须修改开关。

我喜欢使用属于你的枚举的TryParse。 所以你可以像这样使用它

 string colorString = ..... colorEnum color; colorEnum.TryParse(colorString, out color); 

或者如果你不关心字符串的情况

 colorEnum.TryParse(colorString, true, out color); 

如果字符串是有效的枚举,则TryParse值为true,否则为false。

从性能的角度来看,由于枚举是作为静态字段实现的,因此parse方法可能最终会对枚举类型进行反思,并尝试一种可能比这种情况更快的GetField方法。 另一方面,如果90%的情况下,颜色为绿色,则情况会非常快……请注意,CLR有时会在内部重新排列代码,根据统计信息更改案例的顺序(实际上,我是不确定它是否那样,但文件声称它可以)。

我使用以下内容,它可以为您提供所有类型的安全性,同时在向Enum添加新值时仍然没有摔倒,它也非常快。

 public static colorEnum? GetColorFromString(string colorString) { colorEnum? retVal = null; if(Enum.IsDefined(typeof(colorEnum), colorString)) retVal = (colorEnum)Enum.Parse(typeof(colorEnum), colorString); return retVal; } 

我在枚举中使用8个项目的测试显示这种方式比切换方法更快。

或者你可以使用(非常慢的方式):

 public static colorEnum? GetColorFromString(string colorString) { foreach (colorEnum col in Enum.GetValues(typeof(colorEnum))) { if (col.ToString().Equals(colorString)) { return col; } } return null; }