Как получить следующее (или предыдущее) значение перечисления в C #

То, как вы это сделаете, полностью зависит от того, как вы представляли значение, когда передавали его через MQTT.

Если вы передали его в двоичном формате - например, вы опубликовали целое число в виде серии байтов - тогда вам также необходимо знать порядок байтов и количество байтов. Скорее всего, это сначала младший байт (поэтому, если целое число в шестнадцатеричном формате было 0x1234, оно передавалось бы как два байта - 0x34, а затем 0x12) и 32 бита.

Если вы передаете двоичный файл между двумя одинаковыми компьютерами, работающими под аналогичным программным обеспечением, то с вами, вероятно, все будет в порядке (если это никогда не изменится), но если компьютеры различаются или программное обеспечение отличается, вы имеете дело с представлениями вашего целое число, которое будет зависеть от используемой вами платформы. Даже использование разных языков на двух концах может иметь значение - Python может представлять одно целое число, а C - другое, даже если они работают на идентичных процессорах.

Таким образом, если вы передаете в двоичном формате, вы действительно должны выбрать машинно-независимое представление.

Если бы вы передавали в двоичном виде и не пытались сделать машинно-независимое представление, код был бы что-то вроде:

byte *payload;
int payload_length;
int result;

if(payload_length < sizeof(int)) {
    HANDLE THIS ERROR
} else {
    result = *(int *)payload;
}

Это проверяет, чтобы убедиться, что имеется достаточно байтов для представления двоичного целого числа и затем использует приведение для извлечения целого числа из полезной нагрузки.

Если вы передаете в двоичном формате в машинно-независимом формате, вам нужно будет выполнить любое преобразование, необходимое для принимающей архитектуры.

Я действительно не рекомендую передавать в двоичном формате, если вы не знаете, что делаете, и не имеете веских причин для этого. Большинство приложений сегодня будут нормально передаваться в виде текста, который можно назвать машинно-независимым представлением.

Наиболее вероятной альтернативой передаче в двоичном виде является текст, который может быть машинно-независимым форматом. Если вы передаете целое число в виде текста, ваш код будет выглядеть примерно так:

byte *payload;
int payload_length;
char payload_string[payload_length + 1];
int result;

memcpy(payload_string, payload, payload_length);
payload_string[payload_length] = '\0';
result = atoi(payload_string);

Этот код использует временный буфер для копирования полезной нагрузки. Нам нужно обрабатывать полезную нагрузку как строку C, а строки C имеют дополнительный байт в конце - '\ 0' - который указывает конец строки. В полезной нагрузке для этого нет места, и индикатор конца строки может или не может быть отправлен как часть полезной нагрузки, поэтому мы гарантируем, что он есть, скопировав полезную нагрузку и добавив ее.

После этого просто вызвать atoi(), чтобы преобразовать строку в целое число.

48
задан leppie 23 September 2013 в 03:19
поделиться

14 ответов

Благодаря всем для Ваших ответов и обратной связи. Я был удивлен получить столь многих из них. Смотря на них и использующий некоторые идеи, я предложил это решение, которое работает лучше всего на меня:

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

красота этого подхода, что это просто и универсально для использования. Реализованный как универсальный дополнительный метод, можно назвать его на любом перечислении этим путем:

return eRat.B.Next();

Уведомление, я использую обобщенный дополнительный метод, таким образом я не должен определять тип на вызов, всего .Next().

58
ответ дан Yahya Hussein 7 November 2019 в 12:05
поделиться

Из комментариев у меня были многие вопрос как: "Почему Вы когда-либо хотели бы использовать перечисление таким образом". Начиная со столь многих из Вас спрошенный, позвольте мне дать Вам свой вариант использования и видеть, соглашаетесь ли Вы тогда:

у меня есть фиксированный массив объектов int[n]. В зависимости от ситуации я хочу перечислить через этот массив по-другому. Таким образом, я определил:

int[] Arr= {1,2,34,5,6,78,9,90,30};
enum eRat1 { A = 0, B=3, C=5, D=8 }; 
enum eRat2 { A, AA,AAA,B,BB,C,C,CC,D }; 

void walk(Type enumType) 
{ 
   foreach (Type t in Enum.GetValues(enumType)) 
   { 
      write(t.ToString() + " = " + Arr[(int)t)]; 
   }
} 

и вызов walk(typeof(eRAt1)) или walk(typeof(eRAt2))

тогда я получаю необходимый вывод

1) обход (typeof (eRAt1))

A = 1
B = 5
C = 78
D = 30

2) walk(typeof(eRAt2))

A = 1
AA = 2
AAA = 34
B = 5
BB = 6
C = 78
CC = 90
D = 30

, Это очень упрощено. Но я надеюсь, объясняет это. Существуют некоторые другие преимущества для этого, как имеющий enum.toString (). Так в основном я использую перечисления в качестве индексаторов.

Настолько использующий решение я могу сделать что-то вроде этого теперь.

В последовательности eRat1 затем оценивают B, C, но в eRat2 это - BB. Таким образом, в зависимости от которой последовательности я интересуюсь, я могу сделать e.next, и в зависимости от enumType я или получу C или BB. Как можно было бы достигнуть этого со словарями?

я думаю это довольно изящное использование перечислений.

0
ответ дан husayt 7 November 2019 в 12:05
поделиться

Я пошел бы с ответом Sung Meister, но сюда являюсь альтернативой:

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

Примечание: много предположений приняли:)

0
ответ дан leppie 7 November 2019 в 12:05
поделиться

Походит на злоупотребление классом Enum мне - но это сделало бы это (предполагающий, что вызов Затем на последнем значении вызовет перенос):

public static eRat Next(this eRat target)
{
    var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().SkipWhile(e => e != target).Skip(1);
    if (nextValueQuery.Count() != 0)
    {
        return (eRat)nextValueQuery.First();
    }
    else
    {
        return eRat.A;
    }
}

И это дало бы Вам предыдущее значение на той же основе:

public static eRat Previous(this eRat target)
{
    var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().Reverse().SkipWhile(e => e != target).Skip(1);
    if (nextValueQuery.Count() != 0)
    {
        return (eRat)nextValueQuery.First();
    }
    else
    {
        return eRat.D;
    }
}
1
ответ дан Gordon Mackie JoanMiro 7 November 2019 в 12:05
поделиться

var затем = (eRat) ((интервал) someRat + 3);

1
ответ дан eglasius 7 November 2019 в 12:05
поделиться

Я могу думать о 2 вещах:

  • eRat. Перечисление B+3
  • . Синтаксический анализ (typeof (((интервал) eRat. B) +3)
1
ответ дан RvdK 7 November 2019 в 12:05
поделиться

Для простого решения Вы могли бы просто извлечь массив из перечисления.

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

Тогда можно перечислить

foreach (eRat item in list)
    //Do something

Или найти следующий объект

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

, Хранение массива лучше, чем извлечение из перечисления каждый раз, когда Вы хотите следующее значение.

, Но если Вы хотите более красивое решение, создайте класс.

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();
    }
}

Инстанцируют

var eRatEnum = new EnumEnumerator<eRat>();

, Выполняют итерации

foreach (eRat item in eRatEnum)
    //Do something

MoveNext

eRatEnum.Seek(eRat.B);
eRatEnum.MoveNext();
eRat nextItem = eRatEnum.Current;
3
ответ дан Chaowlert Chaisrichalermpol 7 November 2019 в 12:05
поделиться

Вы могли упростить его и обобщить его некоторые:

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

РЕДАКТИРОВАНИЕ : Обратите внимание что, если Ваше перечисление будет содержать дублирующиеся значения (синонимичные записи), то это ( или любая другая техника, перечисленная здесь ), перестанет работать, учитывая одно из тех значений. Например:

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

или, Учитывая BRUSHSTYLE.NULL или, учитывая BRUSHSTYLE.HOLLOW, возвращаемое значение было бы BRUSHSTYLE.HOLLOW.

< leppie>

Обновление: версия дженериков:

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:

Ваша универсальная версия позволяет тому случайно передавать неперечисление значений, которое будет поймано только во времени выполнения. Я первоначально записал это как дженерик, но когда компилятор отклонил where T : Enum, я вынул его и понял, что не получал много от дженериков так или иначе. Единственный реальный недостаток состоит в том, что необходимо бросить результат назад к определенному перечислимому типу.

3
ответ дан P Daddy 7 November 2019 в 12:05
поделиться

Судя по Вашему описанию, Вы не делаете действительно , хотят перечисление. Вы расширяете перечисление вне его возможностей. Почему бы не создать пользовательский класс, который представляет значения, в которых Вы нуждаетесь как свойства при хранении их в OrderedDictionary. Тогда получение следующего/предыдущего было бы тривиально. - обновление

, Если Вы хотите перечислить по-другому на наборе, базирующемся в контексте, сделайте ту явную часть своего дизайна. Инкапсулируйте объекты в классе и имейте немного методов каждый возврат IEnumerable, где, T является Вашим желаемым типом.

, Например

IEnumerable<Foo> GetFoosByBar()
IEnumerable<Foo> GetFoosByBaz()

и т.д.

4
ответ дан Krzysztof Kozmic 7 November 2019 в 12:05
поделиться

Вы заблокированы в использование перечисления чем-то, что Вы не имеете никакого контроля?

, Если бы Вы не, я предложил бы использовать альтернативу, вероятно Dictionary<string, int> rat;

, Если Вы создаете Dictionary, и Вы заполняете ее со своими данными, перечисляющий по нему несколько более просто. Кроме того, это - более четкое отображение намерения - Вы отображаете числа на строки с этим перечислением, и Вы пытаетесь усилить то отображение.

, Если бы необходимо использовать перечисление, я предложил бы что-то еще:

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

, пока Вы добавляете значения, чтобы и Вы сохраняете его в синхронизации, Вы значительно упрощаете действие получения следующего eRat.

4
ответ дан Greg D 7 November 2019 в 12:05
поделиться

Работы до "C" с тех пор никто не отвечает на том, что возвратиться после "D".

[update1]: Обновленный согласно предложению Marc Gravell.

[update2]: Обновленный согласно тому, как требуемый husayt's - возвращает "A" для следующего значения "D".

public class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Next enum of A = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.A));
        Console.WriteLine("Next enum of B = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.B));
        Console.WriteLine("Next enum of C = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.C));
    }
}

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

public class eRatEnumHelper
{
    public static eRat GetNextEnumValueOf(eRat value)
    {
        return (from eRat val in Enum.GetValues(typeof (eRat)) 
                where val > value 
                orderby val 
                select val).DefaultIfEmpty().First();
    }
}

Результат

Следующее перечисление = B
Следующее перечисление B = C
Следующее перечисление C = D
Следующее перечисление D =

10
ответ дан dance2die 7 November 2019 в 12:05
поделиться

Проблема, с которой Вы имеете дело, состоит в том, потому что Вы пытаетесь заставить перечисление делать что-то, что она не была должна. Они, как предполагается, безопасны с точки зрения типов. Присвоение значений интеграла к перечислению позволяется так, чтобы можно было объединить их, но если Вы хотите, чтобы они представили интегральные значения, используйте классы или структуры. Вот возможная альтернатива:

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
}

Это позволяет Вам делать это:

int something = eRat.A + eRat.B;

и это

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

действительно необходимо только использовать перечисления, когда можно извлечь выгоду из их безопасности типов. Если Вы полагаетесь на них, чтобы представить тип, переключиться на константы или на классы.

РЕДАКТИРОВАНИЕ

я предложил бы, чтобы Вы смотрели на страницу MSDN на Дизайн Перечисления. Первая лучшая практика:

Действительно используют перечисление для сильного ввода параметров, свойств и возвращаемых значений, которые представляют наборы значений.

я пытаюсь не обсудить догму, таким образом, я не буду, но здесь являюсь проблемой, Вы собираетесь столкнуться. Microsoft не хочет, чтобы Вы сделали то, что Вы пытаетесь сделать. Они явно просят, чтобы Вы не сделали то, что Вы пытаетесь сделать. Делание его трудно, чтобы Вы сделали то, что Вы пытаетесь сделать. Для выполнения то, что Вы пытаетесь сделать, необходимо создать служебный код, чтобы вынудить это, казаться, работать.

Вы назвали свое решение изящным несколько раз, и это могло бы быть, если бы перечисления были разработаны по-другому, но так как перечисления - каковы они, Ваше решение не изящно. Я думаю, что камерная музыка изящна, но если бы музыканты не имели надлежащих инструментов и должны были играть Vivaldi с полотнами пил и кувшинами, то это больше не было бы изящно, независимо от того, насколько способный они были как музыканты, или насколько хороший музыка была на бумаге.

12
ответ дан Michael Meadows 7 November 2019 в 12:05
поделиться

Вы действительно потребность обобщить эту проблему? Можно ли просто сделать это вместо этого?

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;
    }
}
21
ответ дан Tim Cooper 7 November 2019 в 12:05
поделиться

Вероятно, немного излишества, но:

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

или если Вы хотите первое, которое численно больше:

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

или для следующего большего численно (выполнение вида самостоятельно):

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

Эй, с LINQ как Ваш молоток, мир полон гвоздей;-p

36
ответ дан Marc Gravell 7 November 2019 в 12:05
поделиться