代码之家  ›  专栏  ›  技术社区  ›  AndyM

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

  •  25
  • AndyM  · 技术社区  · 14 年前

    我刚刚发现了一个微妙的bug,其中我有一个枚举,有两个名称不知道地共享相同的数值(在本例中,红色=10,深红色=10)。我有点惊讶这不是语法错误。

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

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

    16 回复  |  直到 7 年前
        1
  •  37
  •   Robin Day    14 年前
    public enum Colour
    {
        Red=10,
        Rouge=10,
        Blue=11,
        Bleu=11,
        Green=12,
        Vert=12,
        Black=13,
        Noir=13
    }
    
        2
  •  24
  •   Walter Stabosz    10 年前

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

        3
  •  19
  •   tanascius    14 年前

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

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

    但请注意,这只是您的枚举用户的糖分。只是因为它被称为 违约 这并不意味着它是初始值。

        4
  •  10
  •   wRAR    14 年前

    枚举的用法与常量相同,并且您可以有两个具有相同值的常量,这些常量在同一位置使用。这可能是因为第三方API,因为向后兼容性或者仅仅是因为业务规则。

        5
  •  6
  •   etc    11 年前

    From the c# language spec :

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

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

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

    在这种情况下,您可以检查mycolor==color.max,这在某些情况下很有用。

        6
  •  4
  •   Arsen Mkrtchyan    14 年前

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

    switch(c)
    {
      Colour.Red:
         break;
      Colour.Crimson:
         break;
      ...
    }
    
        7
  •  3
  •   John Rudy    14 年前

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

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

    至于现实世界中的情况,我一时冲动想不出什么,但我仍然确信,在某些情况下,它可能会有所帮助。

        8
  •  2
  •   Noldorin    14 年前

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

    您提出的场景可能就是这样一个例子。一个更好的,直接从BCL,是 System.Windows.Forms.MessageBoxIcon 埃努姆; Stop , Error Hand 成员都具有相同的描述,实际上具有相同的值。 Asterisk Information 也完全相同,如注释所示:

    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.
    

    希望这能让你对适当的场景有一个很好的了解(你自己可能就是其中之一)。

        9
  •  1
  •   Mau    14 年前

    很好。您可以拥有两个不同于API用户观点的值,但在功能上可以被视为相同的值。

        10
  •  1
  •   Mark Schultheiss    14 年前

    通过命名值而不是实际值使用是根。假设你有同样价值的法语、英语等。这是枚举的根。

        11
  •  1
  •   El Ronnoco    12 年前

    有时建议(尽管 微软推荐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
    }
    

    为了验证/迭代每个可能的设置。虽然我觉得.NET可以提供一个这样的工具:)

        12
  •  1
  •   vent    11 年前

    这是有效的,允许使用不同的名称引用相同的值。 注意这一点在单程上很有效。如果从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
    
        13
  •  1
  •   LukeK    8 年前

    这个例子将说明为什么这是有用的。当你在公共图书馆工作时,以不同的方式命名相同的事物可能是有用的,它是专门为公共使用的。

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

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

        14
  •  0
  •   Phil Gan    14 年前

    我在.NET TWAIN包装器中看到过同样的事情——它允许所有的TWAIN消息代码存储在一个大的枚举中,但它一开始的确让事情变得有点混乱。

        15
  •  0
  •   Despertar    12 年前

    我认为重复使用同一个号码有很多用途。为了给出一个新的例子,假设您有一个排名系统,它将确保在依赖于某个类(父类)的其他类(子类)之前创建特定类(父类)的对象,您可能有一些处于同一“层”中的子类,而不考虑先创建哪个类。在下面的示例中,首先创建父级,然后创建子级1、2或3,最后创建子级4。如果将其视为树图,则具有相同编号的任何项都将是“同级”。

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

    虽然我可以看出你的观点,但这很容易出错。在这种情况下,如果Visual Studio有一个选项来启用允许编译的警告,但如果使用同一个数字两次,则会引发警告,这将非常方便。

        16
  •  0
  •   Stephen Turner    7 年前

    我认为它对字段映射很有用,例如(在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或triparse的结果不一致,此代码输出:

    TaskName
    TaskName
    IsActive
    IsActive