Перечисление как использование флага, установка и смещение

У меня есть два флага:

[Flags]
enum Flags
{
  A = 1,
  B = 2
};

Я поставил их так:

Mode = Flags.A | Flags.B; // default value
for(int i = 0; i < args.Length; i++) {
switch(args[i])
{
  case "--a":
  {
    if ((Mode & Flags.A) == Flags.A && (Mode & Flags.B) == Flags.B) 
     // both, default assume
    {
      Mode = Flags.A; // only A
    }
    else
    {
      Mode |= Flags.A; // append A
    }
    break;
  }
  case "--b":
  {
    if ((Mode & Flags.A) == Flags.A && (Mode & Flags.B) == Mode.B)
    {
      Mode = Flags.B;
    }
    else
    {
      Mode |= Flags.B;
    }
    break;
  }
} }

и использовать их позже следующим образом:

if((Mode & Flags.A) == Flags.A)
{
 //
}
if((Mode & Flags.B) == Flags.B)
{
 //
}

Основная оговорка: могут быть установлены оба флага. Или только один, в этом случае выполняется только одна часть кода.

Мой код хорош? Как лучше установить флаги?

Upd: это менее уродливо, чем первое, как вы думаете?

Mode = 0; // default value now is empty
for(int i = 0; i < args.Length; i++) {
switch(args[i])
{
  case "--a":
  {
    Mode |= Flags.A;
    break;
  }
  case "--b":
  {
    Mode |= Flags.B;
    break;
  }
} }
if(Mode == 0)
{
  Mode = Flags.A | Flags.B; // if no parameters are given, setup both flags
}

person abatishchev    schedule 24.02.2009    source источник
comment
Ваш код синтаксически правильный, но трудно сказать, хорош ли он, не разобравшись в вашей проблеме. Ваш вопрос немного расплывчатый, и ваши комментарии к ответам делают его еще более расплывчатым. Можете ли вы дать немного больше? На первый взгляд, ваше решение слишком сложно для проблемы в представленном виде.   -  person Simon    schedule 24.02.2009
comment
Привет. Существует значение по умолчанию A|B. Если задан параметр --a, установить режим только в A, если --b только в B, и если оба заданы (по умолчанию) A|B. Как лучше всего проверить, является ли текущее значение значением по умолчанию (A|B), чтобы при необходимости изменить его на A или B.   -  person abatishchev    schedule 24.02.2009


Ответы (3)


Вот как я бы установил свои флаги:

Mode = 0;
for(int i = 0; i < args.Length; i++) {
    switch(args[i]) {
    case "--a":
        Mode |= Flags.A;
        break;
    case "--b":
        Mode |= Flags.B;
        break;
    }
}

Если оба флага должны быть включены по умолчанию, я думаю, имеет смысл изменить параметры командной строки на что-то вроде --not-a и --not-b. Это отразит настройку по умолчанию и позволит вам избавиться от (Mode & Flags.A) == Flags.A && (Mode & Flags.B) == Flags.B, что довольно уродливо, ИМХО.

Затем вы можете установить свои флаги следующим образом:

Mode = Flags.A | Flags.B;
for(int i = 0; i < args.Length; i++) {
    switch(args[i]) {
    case "--not-a":
        Mode &= ~Flags.A;
        break;
    case "--not-b":
        Mode &= ~Flags.B;
        break;
    }
}

Наконец, если у вас много флагов (вместо двух), может быть проще настроить перечисление следующим образом:

[Flags]
enum Flags
{
    A = 1,
    B = 1 << 1,
    C = 1 << 2,
    D = 1 << 3,
    E = 1 << 4,
    F = 1 << 5
};
person Can Berk Güder    schedule 24.02.2009
comment
Основное замечание касается значения по умолчанию: A | Б. Так что недостаточно просто добавить |=. - person abatishchev; 24.02.2009
comment
Я согласен с уродством этого кода, посмотрите, пожалуйста, заголовок, что вы думаете? - person abatishchev; 24.02.2009
comment
Новый код намного лучше, но я все еще думаю, что --not-a и --not-b имеют больше смысла. С другой стороны, Mode никогда не будет нулевым (вы устанавливаете его равным 0), поэтому вам следует проверить Mode == 0. - person Can Berk Güder; 24.02.2009

Вы можете отключить «бит» с помощью следующего замечательного утверждения:

Mode &= ~Flags.A;

Я бы также рекомендовал включить «нулевое» значение в ваше перечисление:

[Flags]
enum Flags
{
  Null = 0;
  A = 1,
  B = 2;
}

Это сделает вашу жизнь проще! :-)

person Dan Byström    schedule 24.02.2009
comment
Спасибо, я посмотрю на &=~ ! Но не согласен с вами по поводу нулевого флага. MSDN рекомендует этого не делать! msdn.microsoft.com/en-us/library/ms229062.aspx Невозможно проверить явно установленный флаг нулевого значения, в отличие от отсутствия установленных флагов. - person abatishchev; 24.02.2009
comment
Он не предназначен для установки какого-либо отдельного бита. Он предназначен для очистки и присвоения определенного значения по умолчанию. И проще проверить, установлен ли бит, набрав if ( (Mode & Flags.A) != Flags.Null. Есть много причин, по которым ваша жизнь будет проще со значением .Null. Поверьте мне в этом один! - person Dan Byström; 24.02.2009
comment
Я согласен с нулевым значением для перечисления в стиле флагов, но Microsoft рекомендует использовать имя None, а не Null, как указано в документе, на который ссылается @abatishchev. - person RenniePet; 14.12.2014

Второй вариант намного лучше - именно так бы я и поступил. Замените Mode == null на Mode == 0.

Mode = 0; // default value now is empty
for(int i = 0; i < args.Length; i++) {
    switch(args[i])
    {
        case "--a":
            Mode |= Flags.A;
            break;

        case "--b":
            Mode |= Flags.B;
            break;
    }
}

if(Mode == 0)
{
    Mode = Flags.A | Flags.B; // if no parameters are given, setup both flags
}
person configurator    schedule 24.02.2009