2

I already searched on how to do a switch on the value instead of the enumeration key in C# but with no result, all the posts I've found says that we don't need to use the value, we can just use the key.

But in my case, I want to use the value because I made an enumeration with multiple keys sharing the same value, here's the code :

public enum PlayerPosition {
    North = 0,
    Top = 0, 
    South = 1,
    Bottom = 1,
    East = 2,
    Right = 2,
    West = 3,
    Left = 3
}


switch (obj.PlayerPosition)
{
    case PlayerPosition.North:
        // some code
        break;
    case PlayerPosition.South:
        // some code
        break;
    case PlayerPosition.East:
        // some code
        break;
    case PlayerPosition.West:
        // some code
        break;
    default:
        throw new ArgumentOutOfRangeException();
}

I think this is working but I don't find it really readable...

What I would like to achieve is something like this :

switch (obj.PlayerPosition)
{
    case PlayerPosition.Top:
    case PlayerPosition.North:
        // some code
        break;
    case PlayerPosition.Bottom:
    case PlayerPosition.South:
        // some code
        break;
    case PlayerPosition.Right:
    case PlayerPosition.East:
        // some code
        break;
    case PlayerPosition.Left:
    case PlayerPosition.West:
        // some code
        break;
    default:
        throw new ArgumentOutOfRangeException();
}

The example above doesn't work because it is a duplicated case label. How could I achieve that ?

EDIT : In this enumeration North/Top, South/Bottom are exactly the same, they just represent the position of the player around a table with 4 chairs. But we have old configuration files who use North/South/East/West and new configuration files who are using Top/Bottom/Right/Left.

11
  • 5
    Those aliassed enums are .... evil. Commented Mar 6, 2018 at 12:08
  • 3
    But in your switch, just pick either North/South or Top/Bottom. You don't need both and can't use both at the same time. Commented Mar 6, 2018 at 12:09
  • 1
    Either you have distinct enum values, then you can use the second version. Or you use the same values for some of the enum members, then you simply use the first version (and use the "primary" enum member). Where's the problem? Commented Mar 6, 2018 at 12:11
  • 2
    If you really need to see both cases, comment the second one. Commented Mar 6, 2018 at 12:14
  • 2
    Just use the new Enum Members. It should work: dotnetfiddle.net/Sf54Sq Commented Mar 6, 2018 at 12:14

5 Answers 5

2

I tested this in a dotnetfiddle: Just using the new members will work:

public enum MyEnum
{
    North  = 0, //old
    Top    = 0, //new
    South  = 1, //old
    Bottom = 1  //new
}

public static void Main()
{
    // Parse "old" from XML config (simulated)
    MyEnum test = (MyEnum)Enum.Parse(typeof(MyEnum),"North");
    //          = MyEnum.North

    switch(test)
    {
        case MyEnum.Top:
            Console.WriteLine("NORTH");
            break;
        case MyEnum.Bottom:
            Console.WriteLine("SOUTH");
            break;
        default:
            Console.WriteLine("Unsupported!");
            break;

    }
}

Will output "NORTH".

Edit

Just a word about the actual problem you are facing: Downward compatibility. What I'd do is on startup check if the configs are compatible with your current program version. If not: go through "upgrade" functions that (save a backup of the old configs and then) transform configs to the current version and save them back to disk.

Sign up to request clarification or add additional context in comments.

Comments

2

Concerning the point about not using multiple enum labels with the same value. Generally speaking, I would agree. However, there are circumstances where you could argue that it does make some sense. The following enum from the .NET System.Drawing libraries is an example:

  public enum RotateFlipType
  {
    Rotate180FlipXY = 0,
    RotateNoneFlipNone = 0,
    Rotate270FlipXY = 1,
    Rotate90FlipNone = 1,
    Rotate180FlipNone = 2,
    RotateNoneFlipXY = 2,
    Rotate270FlipNone = 3,
    Rotate90FlipXY = 3,
    Rotate180FlipY = 4,
    RotateNoneFlipX = 4,
    Rotate270FlipY = 5,
    Rotate90FlipX = 5,
    Rotate180FlipX = 6,
    RotateNoneFlipY = 6,
    Rotate270FlipX = 7,
    Rotate90FlipY = 7,
  }

This enum is used to represent the type of rotation or "flip" to perform on an image. Note that some values are the same because, e.g., rotating 180 degrees is equivalent to flipping the X and Y axis.

Even in this example, there are probably other ways to represent the enum without duplicating values, but this method may be the most user-friendly.

I don't see anything inherently wrong with duplicating values, and indeed it is supported. However, you aren't able to use these duplicate enum values in structures such as switch statements.

Comments

1

You should modify the parser for the configuration files to solve this before it even becomes a problem.

Your program should only ever be ONE version at a time. The way it is now, you have 2 versions of configuration files, and you're trying to maintain 2 versions of the code at the same time.

The normal way to handle older versions of configuration files is to convert the data to the new format when they are read, or to detect them when they are first opened and convert them on disk to the new version (optionally notifying the user).

7 Comments

Nitpick-mode on: That's a solution to the problem but not to the question ... (I agree , though)
Fildor is right, but this is certainly what I'll end up doing. Modifying the config file when read is certainly to way to keep only one version in the code.
@Fildor: Yep. That's the way the XY problem is usually answered.
@MarkBenningflied I didn't know what was the XY problem, thanks !
@Fildor: That's true, but I've also known users to DV a post just because they had a toothache at the time, so it doesn't really do any good to worry about that. Now, if ten of them DV the thing, there might just be a problem with it.
|
0

You cannot do this with an enum. The purpose of an enum is that each item will have a different value and can be distinguished from the others. Why would you have Top and North being the same thing when instead you can always use North and avoid the confusion of having Top in addition? I would personally just have North, South, East and West and remove the others.

However, as far as I am aware, this should work:

public enum PlayerPosition {
    North,
    Top, 
    South,
    Bottom,
    East,
    Right,
    West,
    Left
}

switch (obj.PlayerPosition)
{
    case PlayerPosition.Top:
    case PlayerPosition.North:
        // some code
        break;
    case PlayerPosition.Bottom:
    case PlayerPosition.South:
        // some code
        break;
    case PlayerPosition.Right:
    case PlayerPosition.East:
        // some code
        break;
    case PlayerPosition.Left:
    case PlayerPosition.West:
        // some code
        break;
    default:
        throw new ArgumentOutOfRangeException();
}

1 Comment

(Did not DV) OP explains why he needs that in the question.
0

I can't understand the reason behind having two different labels for the same enum value without having two separate enums. Firslty to answer your question you could cast the enum value to an int and then do a comparison on the int...

int value =  (int)obj.PlayerPosition

But I would probably look at removing the duplicate values and having two enums

public enum PlayerPosition {
    Top = 0, 
    Bottom = 1,
    Right = 2,
    Left = 3
}

public enum CompassPosition {
    North = 0, 
    South= 1,
    East= 2,
    West = 3
}

If you wanted to convert between the two you could just cast, e.g.

PlayerPosition pos = PlayerPosition.Left;
CompassPosition compass = (CompassPosition)pos;
Console.WriteLine(compass.ToString());

8 Comments

Just using the new enum Members will also work. I.e.: for example parsed from XML: value = PlayerPosition.North will enter the case PlayerPosition.Top. I tested this in a fiddle (see my comment to the question)
@Hoots I can't do that with two separate enums, the thing here is that the enum will be parsed from an XML file, and deserialized into an object who holds the PlayerPosition.
OK, I would probably still have two enums... Use the PlayerPosition for everything except for when reading from the Xml file where a conversion to the PlayerPosition would happen.
What about Serialization? If internally it's 0, is it north or top 0?
I think this solution will be the hardest to realize, I don't really want to bother with conversion since the deserialization to my object handle this for me. That's a good point, I should test to see which key it will takes.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.