How to get next (or previous) enum value in C#

后端 未结 24 1902
深忆病人
深忆病人 2020-12-04 10:59

I have an enum which is defined like this:

public enum eRat { A = 0, B=3, C=5, D=8 };

So given value eRat.B, I want to get the

相关标签:
24条回答
  • 2020-12-04 11:26

    Probably a bit overkill, but:

    eRat value = eRat.B;
    eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
            .SkipWhile(e => e != value).Skip(1).First();
    

    or if you want the first that is numerically bigger:

    eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
            .First(e => (int)e > (int)value);
    

    or for the next bigger numerically (doing the sort ourselves):

    eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
            .Where(e => (int)e > (int)value).OrderBy(e => e).First();
    

    Hey, with LINQ as your hammer, the world is full of nails ;-p

    0 讨论(0)
  • 2020-12-04 11:26

    Do you really need to generalize this problem? Can you just do this instead?

    public void SomeMethod(MyEnum myEnum)
    {
        MyEnum? nextMyEnum = myEnum.Next();
    
        if (nextMyEnum.HasValue)
        {
            ...
        }
    }
    
    public static MyEnum? Next(this MyEnum myEnum)
    {
        switch (myEnum)
        {
            case MyEnum.A:
                return MyEnum.B;
            case MyEnum.B:
                return MyEnum.C;
            case MyEnum.C:
                return MyEnum.D;
            default:
                return null;
        }
    }
    
    0 讨论(0)
  • 2020-12-04 11:28

    Are you locked into using an enum by something that you have no control over?

    If you're not, I'd suggest using an alternative, probably Dictionary<string, int> rat;

    If you create a Dictionary and you populate it with your data, enumerating over it is somewhat simpler. Also, it's a clearer mapping of intent-- you're mapping numbers to strings with this enum and you're trying to leverage that mapping.

    If you must use the enum, I'd suggest something else:

    var rats = new List<eRat>() {eRat.A, eRat.B, eRat.C, eRat.D};
    

    As long as you're adding the values in-order and you keep it in sync, you greatly simplify the act of retrieving the next eRat.

    0 讨论(0)
  • 2020-12-04 11:28

    I would go with Sung Meister's answer but here is an alternative:

    MyEnum initial = MyEnum.B, next;
    
    for (int i = ((int) initial) + 1, i < int.MaxValue; i++)
    {
      if (Enum.IsDefined(typeof(MyEnum), (MyEnum) i))
      {
         next = (MyEnum) i;
         break;
      }
    }
    

    Note: many assumptions assumed :)

    0 讨论(0)
  • 2020-12-04 11:31

    You could simplify it and generalize it some:

    static Enum GetNextValue(Enum e){
        Array all = Enum.GetValues(e.GetType());
        int i = Array.IndexOf(all, e);
        if(i < 0)
            throw new InvalidEnumArgumentException();
        if(i == all.Length - 1)
            throw new ArgumentException("No more values", "e");
        return (Enum)all.GetValue(i + 1);
    }
    

    EDIT: Note that if your enum contains duplicate values (synonymous entries), then this (or any other technique listed here) will fail, given one of those values. For instance:

    enum BRUSHSTYLE{
        SOLID         = 0,
        HOLLOW        = 1,
        NULL          = 1,
        HATCHED       = 2,
        PATTERN       = 3,
        DIBPATTERN    = 5,
        DIBPATTERNPT  = 6,
        PATTERN8X8    = 7,
        DIBPATTERN8X8 = 8
    }
    

    Given either BRUSHSTYLE.NULL or BRUSHSTYLE.HOLLOW, the return value would be BRUSHSTYLE.HOLLOW.

    <leppie>

    Update: a generics version:

    static T GetNextValue<T>(T e)
    {
      T[] all = (T[]) Enum.GetValues(typeof(T));
      int i = Array.IndexOf(all, e);
      if (i < 0)
        throw new InvalidEnumArgumentException();
      if (i == all.Length - 1)
        throw new ArgumentException("No more values", "e");
      return all[i + 1];
    }
    

    </leppie>

    @leppie:

    Your generic version allows one to accidentally pass a non-enum value, which will be caught only at run-time. I had originally written it as a generic, but when the compiler rejected where T : Enum, I took it out and realized that I wasn't gaining much from generics anyway. The only real drawback is that you have to cast the result back to your specific enum type.

    0 讨论(0)
  • 2020-12-04 11:31

    There is a very simple solution (if you can change your integer values) that is specifically designed to work with numbers. The fact that your number is an enum, isn't a problem. It is still the integer (or whatever underlying number type you assign). Enum just adds the complexity of a cast requirement.

    Assume your enum is defined like this:

     public enum ItemStatus
        {
            New = 0,
            Draft = 1,
            Received = 2,
            Review = 4,
            Rejected = 8,
            Approved = 16
        }
    
    ItemStatus myStatus = ItemStatus.Draft;
    

    Use bitwise operations on the Enum. For Example:

    myStatus = (ItemStatus)(((int)myStatus) << 1)
    

    The result is of myStatus is: ItemStatus.Received.

    You can also go backwards down the Enum by changing the bitwise operator from << to >>.

    myStatus = (ItemStatus)(((int)myStatus) >> 1)
    

    The result is of myStatus is: ItemStatus.New.

    You should always add code to test for an "out of bounds" situation in both directions.

    You can understand more about bitwise operations here: http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301

    0 讨论(0)
提交回复
热议问题