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

发布于 2024-09-08 01:45:00 字数 297 浏览 3 评论 0原文

我刚刚发现了一个微妙的错误,其中我有一个枚举,其中两个名称无意中共享相同的数值(在本例中为 red=10 和 crimson=10)。我有点惊讶这不是语法错误。

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

是否有任何现实世界的原因可以解释为什么这种行为可能有用或者确实认为它应该是语法错误?

I just discovered a subtle bug where I had an enum with two names unintentially sharing the same numeric value (in this case red=10 and crimson=10). I'm a bit surprised this isn't a syntax error.

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

Is there any real world reason why this behaviour might be a useful or do think it should be a syntax error?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(20

颜漓半夏 2024-09-15 01:45:00
public enum Colour
{
    Red=10,
    Rouge=10,
    Blue=11,
    Bleu=11,
    Green=12,
    Vert=12,
    Black=13,
    Noir=13
}
public enum Colour
{
    Red=10,
    Rouge=10,
    Blue=11,
    Bleu=11,
    Green=12,
    Vert=12,
    Black=13,
    Noir=13
}
薄荷梦 2024-09-15 01:45:00

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

Beware! If your enum has multiple elements with the same value, you may get unexpected results when you use Enum.Parse(). Doing so will arbitrarily return the first element that has the requested value. For example, if you have enum Car { Ford = 1, Chevy = 1, Mazda = 1}, then (Car)Enum.Parse(typeof(Car), "1") will return Car.Ford. While that might be useful (I'm not sure why it would be), in most situations it's probably going to be confusing (especially for engineers maintaining the code) or easily overlooked when problems arise.

放血 2024-09-15 01:45:00

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

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

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

I have seen that this feature is sometimes used for a "default" value:

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

But pay attention, this is only sugar for the user of your enum. Just because it is called Default it does not mean that it is the initial value.

掩饰不了的爱 2024-09-15 01:45:00

枚举的使用方式与常量类似,并且您绝对可以在相同的位置使用两个具有相同值的常量。之所以会这样,是因为第 3 方 API、因为向后兼容性,而不仅仅是因为业务规则。

Enums are used like constans and you definitely can have two constants with the same value which are used in the same places. It can be so because of 3rd party API, because of backward compatibility ot just because of business rules.

梦忆晨望 2024-09-15 01:45:00

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

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

Enum is Enumeration of constant variables, and you can have two items with the same value,there is no reason to be a syntax error I think, however, this will cause compile error in this code

switch(c)
{
  Colour.Red:
     break;
  Colour.Crimson:
     break;
  ...
}
葬シ愛 2024-09-15 01:45:00

根据 C# 语言规范

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

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

显示了一个枚举,其中两个枚举成员(Blue 和 Max)具有相同的关联值。

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

From the c# language spec:

Multiple enum members may share the same associated value. The example

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

shows an enum in which two enum members—Blue and Max—have the same associated value.

In this case you could check for MyColor == Color.Max which would be useful is some circumstances.

诗酒趁年少 2024-09-15 01:45:00

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

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

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

It's not a syntax error. All an enum does is enumerate a series of constants in a strongly-typed fashion.

Thus, if a developer mistypes (as in your example), as far as the CLR is concerned, that's a perfectly valid case. The CLR assumes that the developer knows what he's doing, and why he elected to do so.

As for real-world cases, I can't come up with any on the spur-of-the-moment, but I'm still certain that there probably are occasions where it'd be helpful.

梦中楼上月下 2024-09-15 01:45:00

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

您所呈现的场景也许就是这样的一种情况。直接来自 BCL 的更好的一个是 System.Windows.Forms.MessageBoxIcon 枚举; StopErrorHand 成员都具有相同的描述,并且实际上具有相同的值。正如评论所建议的,星号和信息也相同:

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.

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

Sure there is, though it's perhaps not too common. If there is an entity/value that is commonly known under two different names, then that is a good reason.

The scenario you have presented is perhaps one such case. An even better one, straight from the BCL, is the System.Windows.Forms.MessageBoxIcon enum; the Stop, Error, and Hand members all have the same description and indeed the same value. Asterisk and Information are also identical, as suggested by the comments:

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.

Hopefully this should give you a good idea of appropiate scenarios (your own probably being one).

骄傲 2024-09-15 01:45:00

没关系。从 API 用户的角度来看,您可能有两个不同的值,但在功能上可以视为相同的值。

It's fine. You could have two values that are different from the point of view of the user of an API, but functionally can be treated as the same value.

尤怨 2024-09-15 01:45:00

使用命名值而不是实际值是根。假设你有相同值的法语、英语等。这对我来说是枚举的根源。

Using by named value as opposed to the actual value is root. Suppose you have French, English etc. with the same value. This is the root of enum to me.

煮茶煮酒煮时光 2024-09-15 01:45:00

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

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

It is sometimes recommended (although not recommended by MS for C#! - see Salaros's comment) to include a lower and upper bound in your enum such as

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

For the purposes of validation/iterating through each possible setting. Though I have a feeling that .Net may provide a facility for this :)

说不完的你爱 2024-09-15 01:45:00

这是有效的,并且允许人们用不同的名称引用相同的值。
请注意,这种方法单方面效果很好。如果从 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

This is valid and allows one to refer same value with different names.
Beware this works well oneway. You may get inconsistent results if you are converting from int/string to enum or while formatting strings.

Eg:

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

Output:

Crimson is Red
倾其所爱 2024-09-15 01:45:00

这个例子将说明为什么这很有用。当您在致力于公共使用的公共图书馆工作时,以不同的方式命名相同的事物可能会很有用。

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

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

This example will show why this is useful. When you are working on public library, which is dedicated to public use, naming same things in different way may be useful.

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

When different words have same meaning in some situations it has sense, to name them. When parsing, it always return good value in this situation.

早乙女 2024-09-15 01:45:00

我目前正在开发一个项目,这实际上是一个有用的功能。

public enum State
{
    NotTransmitted = 0,
    Deleted = 0,
    Transmitted = 1,
    Deactivated = 1,
    Activated = 2
}

NotTransmissed 和Deleted 状态在编程上是相同的,对于实际情况的软件来说并不重要。在这两种情况下,软件都必须将该项目传输到接收器。

话虽这么说,对于程序员来说,删除后将状态设置为“已删除”比将其设置为“未传输”要直观得多。发送后将其设置为“已发送”而不是将其设置为“停用”也是如此。

简而言之,它增强了代码的可读性。

I am currently working on a project where this is actually a usefull feature.

public enum State
{
    NotTransmitted = 0,
    Deleted = 0,
    Transmitted = 1,
    Deactivated = 1,
    Activated = 2
}

The states NotTransmitted and Deleted are programmatically identical and it does not matter for the software which is the actual case. In both cases the software will have to f.e. transmit this item to a receiver.

That being said, it is far more intuitive for a programmer to set the state to "Deleted" after deleting it than to set it to "NotTransmitted". The same goes for setting it to "Transmitted" after transmitting it over setting it to "Deactivated".

So in short it enhances readability of code.

沫离伤花 2024-09-15 01:45:00

Obsolete 怎么样?

我们遇到过这样的情况,无论出于何种原因,我们需要更改附带库中枚举值的名称。我相信它们的用法略有变化,并且它们在支持数据存储中被重新标记。

您可以争论许多其他选项,例如废弃整个枚举并添加第二个,或者为新选项使用新值(有原因,但我听到了),但我不认为我可以争论为什么任何在这一点上本质上是“正确的”。

无论如何......

public enum Colour
{
    [Obsolete("The colour Red will soon be replaced with Crimson. Please update your usage.")]
    Red = 10,
    Blue = 11,
    Green = 12,
    Crimson = 10
}

如果我们不能两次使用相同的值,我们就无法在版本之间使名称过时

比尔的警告成立

Console.WriteLine(Colour.Red);
Console.WriteLine(Colour.Crimson);

它们都将 Red 输出到控制台。引用莫德的话说,“你可以想象它从这里会走向何方。”

How about with Obsolete?

We had a case where, for whatever reason, we needed to change the name of the enum's values in a shipped library. I believe their usage changed slightly and they were relabeled in the backing datastore.

You could argue for a number of other options, like obsolete the whole enum and add a second, or use new values for the new options (there are reasons, but I hear you), but I don't think I can argue why any are inherently "right-er" at this point.

In any event...

public enum Colour
{
    [Obsolete("The colour Red will soon be replaced with Crimson. Please update your usage.")]
    Red = 10,
    Blue = 11,
    Green = 12,
    Crimson = 10
}

Had we not been able to use the same value twice, we would not have been able to make a name Obsolete like this between versions.

But Bill's warning holds.

Console.WriteLine(Colour.Red);
Console.WriteLine(Colour.Crimson);

Those both output Red to the console. To quote Maude, "You can imagine where it goes from here."

檐上三寸雪 2024-09-15 01:45:00

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

I've seen the same thing in a .net TWAIN wrapper - it allows all the TWAIN message codes to be stored in one big enum, but it does make things a bit confusing at first.

鸠魁 2024-09-15 01:45:00

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

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

尽管我可以理解你的观点,因为这很容易犯错误。在这种情况下,如果 Visual Studio 有一个启用警告的选项,可以让其编译,但如果使用相同的数字两次,则会发出警告,这会很方便。

I think there are many uses for re-using the same number. To give a new example, say you have a ranking system which will ensure that objects of a particular class (Parent) are created before other classes that are dependent on it (Children), you may have some children who are in the same 'tier' and it does not matter which one is created first. In the example below, Parent would be created first, Child 1, 2, or 3 next, then last would be Child4. If this were viewed as a tree diagram, any items with the same number would be 'siblings'.

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

Although I can see your point of view in that this could be easy to do by mistake. In that case it would be handy if visual studio had an option to enable warnings which would let it compile but would raise a warning if the same number was used twice.

感情洁癖 2024-09-15 01:45:00

我认为这对于字段映射很有用,例如(在 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

I thought it would be useful for field mapping, for example (in 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
}

The aim is use the shorter of the names, however the results from Parse or TryParse are not consistent and this code outputs:

TaskName
TaskName
IsActive
IsActive
五里雾 2024-09-15 01:45:00
    public enum SortBy
    {
        Ascending = 0,
        Descending = 1,
        Asc = 0,
        Desc = 1
    }

这就是为什么这个解决方案对我有用

    public enum SortBy
    {
        Ascending = 0,
        Descending = 1,
        Asc = 0,
        Desc = 1
    }

This is why this solution was useful for me

美羊羊 2024-09-15 01:45:00

Microsoft 的代码分析包括规则 CA1069:枚举不应有重复的值

但是,该规则仅适用于将相同的数字文字显式分配给枚举的两个不同名称。它不适用于将以前的名称分配给新名称。 规则说明部分 说(强调我的):

每个枚举成员都应该具有唯一的常量值或者显式分配给枚举中的先前成员以表明共享值的明确意图。

据我了解,微软明确表示,可以使用两个枚举名称来表示相同的值,但不要使用像这样的重复数字…………

public enum Colour
{
    Red=10,
    Blue=11,
    Green=12,
    Crimson=10 // Duplicate specified with number.
}

显式地将名称与名称等同起来更不容易出错。以前的名字...

public enum Colour
{
    Red=10,
    Blue=11,
    Green=12,
    Crimson=Red // Duplicate specified with name.
}

当然,正如其他答案中所讨论的那样,转换为字符串仍然存在问题。

Microsoft's code analysis includes rule CA1069: Enums should not have duplicate values.

However, that rule only applies to explicitly assigning the same numeric literal to two different names of the enum. It does not apply to assigning a previous name to a new name. The Rule Description section says (emphasis mine):

Every enum member should either have a unique constant value or be explicitly assigned with a prior member in the enum to indicate explicit intent of sharing value.

As I understand it, Microsoft is explicitly saying that it is OK to have two enum names for the same value, but instead of using a duplicate number like this...

public enum Colour
{
    Red=10,
    Blue=11,
    Green=12,
    Crimson=10 // Duplicate specified with number.
}

...it is less error prone to explicitly equate a name with a previous name...

public enum Colour
{
    Red=10,
    Blue=11,
    Green=12,
    Crimson=Red // Duplicate specified with name.
}

Of course, there are still the issues with conversion to a string, as discussed in other answers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文