Compare enum values for being greater than or less than

93 Views Asked by At

My question may seem dumb, but I couldn't find a proper answer for it after searching for a while.

Imagine we have an enum called MissionStateEnum as below(since I am a c# developer I'm writing my code in c#, but I guess my question is a general so I will appreciate any further helps)

enum MissionStateEnum{
    Pending = 1,
    Assigned = 2,
    Started = 3,
    Done = 4,
    Canceled = 5
}

Now we would like to check if the state of a mission is pending, assigned or one of started, done or cancelled to decide something based on one of those 3 conditions.

The common and best approach I know and used so many times is to use a switch case:

public void CheckMissionState(MissionStateEnum status)
{
    switch (status)
    {
        case MissionStateEnum.Pending:
        {
            //Do something based on Pending
            break;
        }     
        case MissionStateEnum.Assigned:
        {
            //Do something based on Assigned
            break;
        }
        case MissionStateEnum.Started:
        case MissionStateEnum.Done:
        case MissionStateEnum.Canceled:
        {
            //Do something based on Started, Done or Canceled
            break;
        }
        default:
            throw new ArgumentOutOfRangeException(nameof(state), state, null);
    }
}

My question is, how about if? our part of the logic is that if the case is higher than the MissionStateEnum.Assigned, can we hanlde this case with a simple 2 line if instead of 10 lines of switch case since the state is higher than MissionStateEnum.Assigned.

if(state > MissionStateEnum.Assigned)
{
    //Do something based on Started, Done or Canceled
    return;
}

Is it okay to use if instead of switch case?

2

There are 2 best solutions below

0
Marian Theisen On

You can use if, but you should absolutely not rely on the integer value of the enum - especially make no assumptions about the order etc. That value is just an implementation detail and the coupling and possible bugs are not worth the "time saved" by not typing out all the switch cases.

(tbh there is no time to be saved because your IDE should do that for you.)

Also your IDE can help you check if you have handled all cases, and if you do not want to handle a specific value, you could include it anyway with a comment why.

1
Peter Csala On

If you always want to treat Started, Done and Cancelled either individually or as a group then you can do something like below.

In other words this solution is not scalable: Lets suppose from tomorrow you need to treat Done and Cancelled as a group or Started and Done together then you should not use this approach.

Marker attribute

[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
class AtLeastStartedAttribute : Attribute {}

public enum MissionStateEnum
{
    Pending = 1,
    Assigned = 2,
    [AtLeastStarted]
    Started = 3,
    [AtLeastStarted]
    Done = 4,
    [AtLeastStarted]
    Canceled = 5
}

Most probably you can come up with a better name than this :)

Extension method

public static class MissionStateEnumExtension
{
    public static bool IsAtLeastStarted(this MissionStateEnum stateEnum)
    {
        var name = Enum.GetName(typeof(MissionStateEnum), stateEnum);
        return typeof(MissionStateEnum).GetField(name)
            .GetCustomAttributes(typeof(AtLeastStartedAttribute), false)
            .Any();
    }
}

Please bear in mind that this code is not dealing with error cases. You should make it more robust before you start using it.

I did not include any error handling to keep the sample simple and easy to follow.

Usage

Console.WriteLine(MissionStateEnum.Assigned.IsAtLeastStarted());

...
if (state.IsAtLeastStarted())
{
  //
}

Dotnet fiddle link: https://dotnetfiddle.net/xhNvbE


As a super minor thing please try to stick with the original naming and do not introduce new terms as aliases. Using state and status interchangeably might not seem a big deal, but it can cause headache for future maintainers.

From

void CheckMissionState(MissionStateEnum status)

To

void CheckMissionState(MissionStateEnum state)