开发者

Why is it okay for an enum to have two different names with the same numeric value?

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开发者_如何学JAVA.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?


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


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.


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.


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.


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;
  ...
}


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.


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.


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).


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.


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.


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 :)


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


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.


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.


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.


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.


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


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

This is why this solution was useful for me

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜