为什么Enum.Parse会创建未定义的条目?

class Program { static void Main(string[] args) { string value = "12345"; Type enumType = typeof(Fruits); Fruits fruit = Fruits.Apple; try { fruit = (Fruits) Enum.Parse(enumType, value); } catch (ArgumentException) { Console.WriteLine(String.Format("{0} is no healthy food.", value)); } Console.WriteLine(String.Format("You should eat at least one {0} per day.", fruit)); Console.ReadKey(); } public enum Fruits { Apple, Banana, Orange } } 

如果您执行上面的代码,结果显示:

你应该每天至少吃一个12345。

我真的希望在传递未知名称(字符串)时抛出ArgumentException。 仔细查看Enum.Parse定义可以看出:

摘要:
将一个或多个枚举常量的名称或数值的字符串表示forms转换为等效的枚举对象。

例外:
ArgumentException :enumType不是枚举。 – 或 – 值是空字符串或仅包含空格。 – 或 – value是一个名称,但不是为枚举定义的命名常量之一

即,如果传递整数的字符串表示,则创建新的枚举值,并且现在设计引发exception。 这有意义吗?

至少我现在知道在Enum.IsDefined(enumType, value)之前调用Enum.IsDefined(enumType, value) Enum.Parse()

“命名常量”是Enum值的文本表示,而不是您分配给它的数字。

如果你改变:

 string value = "12345"; 

至:

 string value = "Cake"; 

您将看到您期望的错误,因为“value是一个名称,但不是为枚举定义的命名常量之一。”。 在这种情况下,您传入的值名称“Cake”,但不是枚举中的名称。

想想Enum.Parse(enumType, value); 执行以下操作:

  1. 如果value是空引用,则抛出ArgumentNullException
  2. 值中的valueenumType中枚举中指定常量之一。 如果是,则从枚举中返回该值并停止。
  3. 值中的value直接转换为基础类型(在本例中为Int32),如果是,则返回该值并停止( 即使该值没有命名常量 )。
  4. 值中的value直接转换为基础类型,但在基础类型的范围之外? 例如,该值是一个包含大于MAXINT的数字的字符串。 如果是,则抛出OverflowException
  5. 值是否不能转换为基础类型? 如果是,抛出ArgumentException。

枚举可以是其基本整数类型的任何值。 它不仅限于命名常量。

例如,以下内容完全有效:

 enum Foo{ A, B, C, D } Foo x = (Foo)5; 

尽管5不对应于命名常量,但它仍然是Foo的有效值,因为Foo的基础类型是Int32

如果要调用x.ToString() ,返回的值将只是“5”,因为没有命名常量与x的值相对应。

Enum.Parse()Enum.Parse()的逆函数。 您应该期望Enum.ToString()可以返回Enum.Parse()可以接受的任何内容。 例如,这包括标志枚举的逗号分隔值:

 [Flags] enum Foo{ A = 1, B = 2, C = 4, D = 8 } Foo x = Foo.A | Foo.B | Foo.C | Foo.D; int i = (int)x; string s = x.ToString(); Console.WriteLine(i); Console.WriteLine(s); Console.WriteLine((Foo)Enum.Parse(typeof(Foo), i.ToString()) == x); Console.WriteLine((Foo)Enum.Parse(typeof(Foo), s) == x); 

输出:

 15
 A B C D
真正
真正

编辑:

你真正想要的是这样的:

 static Enum GetEnumValue(Type enumType, string name){ // null-checking omitted for brevity int index = Array.IndexOf(Enum.GetNames(enumType), name); if(index < 0) throw new ArgumentException("\"" + name + "\" is not a value in " + enumType, "name"); return Enum.GetValues(enumType).GetValue(index); } 

或不区分大小写的版本:

 static Enum GetEnumValue(Type enumType, string name, bool ignoreCase){ // null-checking omitted int index; if(ignoreCase) index = Array.FindIndex(Enum.GetNames(enumType), s => string.Compare(s, name, StringComparison.OrdinalIgnoreCase) == 0); // or StringComparison.CurrentCultureIgnoreCase or something if you // need to support fancy Unicode names else index = Array.IndexOf(Enum.GetNames(enumType), name); if(index < 0) throw new ArgumentException("\"" + name + "\" is not a value in " + enumType, "name"); return Enum.GetValues(enumType).GetValue(index); } 

你需要使用Enum.IsDefined:

http://msdn.microsoft.com/en-us/library/essfb559.aspx

 using System; [Flags] enum Colors { None=0, Red = 1, Green = 2, Blue = 4 }; public class Example { public static void Main() { string[] colorStrings = { "0", "2", "8", "blue", "Blue", "Yellow", "Red, Green" }; foreach (string colorString in colorStrings) { try { Colors colorValue = (Colors) Enum.Parse(typeof(Colors), colorString); 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); } catch (ArgumentException) { Console.WriteLine("'{0}' is not a member of the Colors enumeration.", colorString); } } } } // The example displays the following output: // Converted '0' to None. // Converted '2' to Green. // 8 is not an underlying value of the Colors enumeration. // 'blue' is not a member of the Colors enumeration. // Converted 'Blue' to Blue. // 'Yellow' is not a member of the Colors enumeration. // Converted 'Red, Green' to Red, Green. 

我个人认为很遗憾Enum.Parse接受数字的字符串表示。 如果您正在寻找替代方案,您可能需要查看我的Unconstrained Melody项目,该项目具有各种解析选项,并且也是强类型的。

您当然可以Enum.IsDefined与解析结合使用。 你肯定接受字符串版本的数字吗? 或者你真的只期待名字?