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

后端 未结 24 1901
深忆病人
深忆病人 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:35

    The problem you're dealing with is because you're trying to get an enum to do something it shouldn't. They're supposed to be type safe. Assigning integral values to an enum is allowed so that you can combine them, but if you want them to represent integral values, use classes or structs. Here's a possible alternative:

    public static class eRat
    {
        public static readonly eRatValue A;
        public static readonly eRatValue B;
        public static readonly eRatValue C;
        public static readonly eRatValue D;
    
        static eRat()
        {
            D = new eRatValue(8, null);
            C = new eRatValue(5, D);
            B = new eRatValue(3, C);
            A = new eRatValue(0, B);
        }
    
        #region Nested type: ERatValue
        public class eRatValue
        {
            private readonly eRatValue next;
            private readonly int value;
    
            public eRatValue(int value, eRatValue next)
            {
                this.value = value;
                this.next = next;
            }
    
            public int Value
            {
                get { return value; }
            }
    
            public eRatValue Next
            {
                get { return next; }
            }
    
            public static implicit operator int(eRatValue eRatValue)
            {
                return eRatValue.Value;
            }
        }
        #endregion
    }
    

    This allows you to do this:

    int something = eRat.A + eRat.B;
    

    and this

    eRat.eRatValue current = eRat.A;
    while (current != null)
    {
        Console.WriteLine(current.Value);
        current = current.Next;
    }
    

    You really should only be using enums when you can benefit from their type safety. If you're relying on them to represent a type, switch to constants or to classes.

    EDIT

    I would suggest you take a look at the MSDN page on Enumeration Design. The first best practice is:

    Do use an enumeration to strongly type parameters, properties, and return values that represent sets of values.

    I try not to argue dogma, so I won't, but here's the problem you're going to face. Microsoft doesn't want you to do what you are trying to do. They explicitly ask you not to do what you are trying to do. The make it hard for you to do what you are trying to do. In order to accomplish what you are trying to do, you have to build utility code to force it to appear to work.

    You have called your solution elegant more than once, and it might be if enums were designed in a different way, but since enums are what they are, your solution isn't elegant. I think that chamber music is elegant, but if the musicians didn't have the proper instruments and had to play Vivaldi with sawblades and jugs, it would no longer be elegant, regardless of how capable they were as musicians, or how good the music was on paper.

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

    var next = (eRat)((int)someRat + 3);

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

    Thanks to everybody for your answers and feedback. I was surprised to get so many of them. Looking at them and using some of the ideas, I came up with this solution, which works best for me:

    public static class Extensions
    {
    
        public static T Next<T>(this T src) where T : struct
        {
            if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argument {0} is not an Enum", typeof(T).FullName));
    
            T[] Arr = (T[])Enum.GetValues(src.GetType());
            int j = Array.IndexOf<T>(Arr, src) + 1;
            return (Arr.Length==j) ? Arr[0] : Arr[j];            
        }
    }
    

    The beauty of this approach, that it is simple and universal to use. Implemented as generic extension method, you can call it on any enum this way:

    return eRat.B.Next();
    

    Notice, I am using generalized extension method, thus I don't need to specify type upon call, just .Next().

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

    For simple solution, you might just extract array from enum.

    eRat[] list = (eRat[])Enum.GetValues(typeof(eRat));
    

    Then you can enumerate

    foreach (eRat item in list)
        //Do something
    

    Or find next item

    int index = Array.IndexOf<eRat>(list, eRat.B);
    eRat nextItem = list[index + 1];
    

    Storing the array is better than extracting from enum each time you want next value.

    But if you want more beautiful solution, create the class.

    public class EnumEnumerator<T> : IEnumerator<T>, IEnumerable<T> {
        int _index;
        T[] _list;
    
        public EnumEnumerator() {
            if (!typeof(T).IsEnum)
                throw new NotSupportedException();
            _list = (T[])Enum.GetValues(typeof(T));
        }
        public T Current {
            get { return _list[_index]; }
        }
        public bool MoveNext() {
            if (_index + 1 >= _list.Length)
                return false;
            _index++;
            return true;
        }
        public bool MovePrevious() {
            if (_index <= 0)
                return false;
            _index--;
            return true;
        }
        public bool Seek(T item) {
            int i = Array.IndexOf<T>(_list, item);
            if (i >= 0) {
                _index = i;
                return true;
            } else
                return false;
        }
        public void Reset() {
            _index = 0;
        }
        public IEnumerator<T> GetEnumerator() {
            return ((IEnumerable<T>)_list).GetEnumerator();
        }
        void IDisposable.Dispose() { }
        object System.Collections.IEnumerator.Current {
            get { return Current; }
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
            return _list.GetEnumerator();
        }
    }
    

    Instantiate

    var eRatEnum = new EnumEnumerator<eRat>();
    

    Iterate

    foreach (eRat item in eRatEnum)
        //Do something
    

    MoveNext

    eRatEnum.Seek(eRat.B);
    eRatEnum.MoveNext();
    eRat nextItem = eRatEnum.Current;
    
    0 讨论(0)
  • 2020-12-04 11:39

    I'm using this, perfect for my.

        //===================================================================================
    // NEXT VALUE IN ENUM 
    // ex: E_CamModes eNew =  kGlobalsVars.eGetNextValue< E_CamModes >( geCmMode );
    public static T eGetNextValue< T >( T eIn ){
        T[] aiAllValues = ( T[] ) Enum.GetValues( typeof( T ));
        int iVal = System.Array.IndexOf( aiAllValues, eIn );
        return aiAllValues[ ( iVal + 1 ) % aiAllValues.Length ];
    }
    
    0 讨论(0)
  • 2020-12-04 11:40

    Old post, but I have an alternative solution

    //Next with looping    
    public static Enum Next(this Enum input)
    {
        Array Arr = Enum.GetValues(input.GetType());
        int j = Array.IndexOf(Arr, input) + 1;
        return (Arr.Length == j) ? (Enum)Arr.GetValue(0) : (Enum)Arr.GetValue(j);
    }
    
    //Previous with looping
    public static Enum Prev(this Enum input)
    {
       Array Arr = Enum.GetValues(input.GetType());
       int j = Array.IndexOf(Arr, input) - 1;
       return (j == -1) ? (Enum)Arr.GetValue(Arr.Length -1) : (Enum)Arr.GetValue(j);
    }
    

    And when you need to use it, just do a cast

    BootstrapThemeEnum theme = BootstrapThemeEnum.Info;
    var next = (BootstrapThemeEnum)theme.Next();
    

    my enum

    public enum BootstrapThemeEnum
    {
        [Description("white")]
        White = 0,
        [Description("default")]
        Default = 1,
        [Description("info")]
        Info = 2,
        [Description("primary")]
        Primary = 3,
        [Description("success")]
        Success = 4,
        [Description("warning")]
        Warning = 5,
        [Description("danger")]
        Danger = 6,
        [Description("inverse")]
        Inverse = 7
    
    }
    
    0 讨论(0)
提交回复
热议问题