为什么枚举有两个不同的名称具有相同的数值?

我刚刚发现了一个微妙的错误,我有一个枚举,两个名字无意中共享相同的数值(在这种情况下,红色= 10和深红色= 10)。 我有点惊讶这不是语法错误。

public enum Colour { Red=10, Blue=11, Green=12, Crimson=10 } // Debug.Write(Colour.Red==Colour.Crimson) outputs True 

是否有任何现实世界的理由为什么这种行为可能有用或者认为它应该是语法错误?

 public enum Colour { Red=10, Rouge=10, Blue=11, Bleu=11, Green=12, Vert=12, Black=13, Noir=13 } 

谨防! 如果您的enum具有多个具有相同值的元素,则在使用Enum.Parse()时可能会出现意外结果。 这样做会随意返回具有请求值的第一个元素。 例如,如果你有enum Car { Ford = 1, Chevy = 1, Mazda = 1} ,那么(Car)Enum.Parse(typeof(Car), "1")将返回Car.Ford 。 虽然这可能有用(我不确定为什么会这样),但在大多数情况下,它可能会令人困惑(特别是对于维护代码的工程师),或者在出现问题时容易被忽视。

我已经看到此function有时用于“默认”值:

 public enum Scope { Transient, Singleton, Default=Transient } 

但要注意,这只是你的枚举用户的糖。 仅仅因为它被称为默认,它并不意味着它是初始值。

枚举像constans一样使用,你肯定可以有两个具有相同值的常量,它们在相同的地方使用。 它可能是因为第三方API,因为向后兼容性仅仅是因为业务规则。

来自c#语言规范 :

多个枚举成员可以共享相同的关联值。 这个例子

 enum Color { Red, Green, Blue, Max = Blue } 

显示一个枚举,其中两个枚举成员 – 蓝色和最大 – 具有相同的关联值。

在这种情况下,您可以检查MyColor == Color.Max,这在某些情况下会很有用。

枚举是常量变量的枚举,你可以有两个具有相同值的项,我认为没有理由是语法错误,但这会导致此代码中的编译错误

 switch(c) { Colour.Red: break; Colour.Crimson: break; ... } 

这不是语法错误。 所有enum都是以强类型的方式枚举一系列常量。

因此,如果开发人员输入错误(如在您的示例中),就CLR而言,这是一个非常有效的案例。 CLR假定开发人员知道他在做什么,以及他选择这样做的原因。

至于现实世界的情况,我无法想出任何关于时刻的事情,但我仍然确定在某些情况下它可能会有所帮助。

当然有,虽然它可能不太常见。 如果存在两个不同名称下通常已知的实体/值,则这是一个很好的理由。

您提出的方案可能就是这种情况。 直接来自BCL的更好的是System.Windows.Forms.MessageBoxIcon枚举; StopErrorHand成员都具有相同的描述和相同的值。 如评论所示, AsteriskInformation也是相同的:

 Asterisk The message box contains a symbol consisting of a lowercase letter i in a circle. Information The message box contains a symbol consisting of a lowercase letter i in a circle. 

希望这应该让你对适当的场景(你自己可能是一个)有个好主意。

没关系。 您可以有两个与API用户的观点不同的值,但在function上可以视为相同的值。

使用命名值而不是实际值是root。 假设您有相同的法语,英语等。 这是我的枚举的根源。

有时建议(尽管MS 推荐C#! – 参见Salaros的评论)在你的枚举中包含一个下限和上限,如

 public enum Colour { LowBound=10, Red=10, Rouge=10, Blue=11, Bleu=11, Green=12, Vert=12, Black=13, Noir=13, UpperBound=13 } 

用于validation/迭代每个可能的设置。 虽然我有一种感觉.Net可能为此提供一个设施:)

这是有效的,允许用不同的名称引用相同的值。 要注意这一点很有效。 如果要从int / string转换为enum或格式化字符串,则可能会得到不一致的结果。

例如:

 public enum Colour { Red=10, Blue=11, Green=12, Crimson=10 } Colour myColor = Colour.Crimson; Console.WriteLine("Crimson is {0}", myColor.ToString()); 

输出:

 Crimson is Red 

此示例将说明这有用的原因。 当您在致力于公共使用的公共图书馆工作时,以不同方式命名相同的东西可能是有用的。

 public enum GestureType { Touch = 1, Tap = 1, DoubleTouch = 2, DoubleTap = 2, Swipe = 3, Slide = 3, ... } 

当某些情况下不同的词语具有相同的含义时,它们就有意义。 在解析时,它总是在这种情况下返回良好的价值。

我在.net TWAIN包装器中看到了同样的东西 – 它允许所有TWAIN消息代码存储在一个大的枚举中,但它确实让事情有点混乱。

我认为重复使用相同数字有很多用途。 举一个新的例子,假设你有一个排名系统,它将确保特定类(Parent)的对象在依赖它的其他类(Children)之前创建,你可能有一些孩子在同一层’并且首先创建哪一个并不重要。 在下面的示例中,将首先创建Parent,然后创建Child 1,2或3,然后是last4。 如果将其视为树形图,则具有相同编号的任何项目都将是“兄弟姐妹”。

 public enum ObjectRanks { Parent = 0, Child1 = 1, Child2 = 1, Child3 = 1, Child4 = 2 } 

虽然我可以看到你的观点,但这可能很容易被误解。 在这种情况下,如果visual studio有一个选项来启用警告可以让它编译但是如果两次使用相同的数字会引发警告,那将会很方便。

我认为它对于字段映射很有用,例如(在LinqPad中):

 void Main() { ((FieldName)Enum.Parse(typeof(FieldName), "Name", true)).ToString().Dump(); ((FieldName)Enum.Parse(typeof(FieldName), "TaskName", true)).ToString().Dump(); ((FieldName)Enum.Parse(typeof(FieldName), "IsActive", true)).ToString().Dump(); ((FieldName)Enum.Parse(typeof(FieldName), "TaskIsActive", true)).ToString().Dump(); } public enum FieldName { Name, TaskName = Name, IsActive, TaskIsActive = IsActive } 

目标是使用较短的名称,但是Parse或TryParse的结果不一致,并且此代码输出:

 TaskName TaskName IsActive IsActive