2016-03-07 3 views
4

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

[Flags] 
public enum MyStatus 
{ 
    OKResponse = 0, 
    ResponseTooBig = 1, 
    ErrorMessage = 2, 
    NoResponse = 4, 
    ... 
} 

Я привык проверять флаги так:

if ((status & MyStatus.OKResponse) != 0) {...} 

, но он не работает для MyStatus.OKResponse, поскольку она равна нулю , Это вовсе не флаг, это отсутствие всех флагов. Конечно, когда я нашел ошибку, я понял, что OKResponse был единственным статусом ошибки, поэтому на самом деле это означает «нет ошибок, никаких флагов». Тем не менее, я действительно не считаю это очевидным.

Это плохая привычка, определяющая 0 как одно из значений в перечислении флагов? Каков рекомендуемый способ? Каков наилучший способ проверить флаги, которые будут работать с флагом «без флагов»?

+5

не только это не вредная привычка, наоборот - это плохо нЕ определить нулевое значение. Это связано с тем, что значение по умолчанию для перечисления равно 0. Соглашением является его «Нет». Кроме того, при использовании '[Flags]' соглашение заключается в плюрализации имени перечисления. Похоже, ваше перечисление должно называться чем-то вроде «Ошибки». –

+2

Кажется неправильным использование перечисления Flags для этого. У вас есть статус, который представлен более чем одним битом? – Steve

+0

@Steve Да, мне пришлось немного анонимизировать пример ... Первый - это OKResponse, а остальное - некоторые флаги ошибок, более чем один из возможных. Использование флажков в порядке, действительно. – vojta

ответ

6

Это плохая привычка, определяющая 0 как одно из значений в перечислении флагов?

Нет, наоборот, как говорят комментарии, он обычно используется 0 в качестве значения для данного флага, и это то, что перечисление будет по умолчанию, если не другое значение не присваивается первый дал стоимость. Как отмечают другие в комментариях, также принято использовать Enum.None в качестве первого значения для перечисления, что делает ваши намерения более ясными для всех, кто читает код.

Каков рекомендуемый способ?

Там не один способ сделать это, но я обычно люблю использовать краткий Enum.HasFlag метод:

void Main() 
{ 
    var status = MyStatus.ResponseTooBig | MyStatus.NoResponse; 
    if (status.Equals(MyStatus.OKResponse)) 
     Console.WriteLine("Status is OKResponse"); 
    else 
     Console.WriteLine($"Has NoResponse?: {status.HasFlag(MyStatus.NoResponse)}"); 
} 
+0

Проблема в том, что 'status.HasFlag (MyStatus.OKResponse)' всегда истинно, поэтому в этом случае это не работает ... См. Http://stackoverflow.com/questions/15436616/hasflags-always-returns-true -for-none-0-value-in-enum – vojta

+0

@vojta Решение находится в том же сообщении: * Если базовое значение флага равно нулю, метод возвращает true. Если это поведение нежелательно, вы можете использовать метод Equals для проверки равенства с нулем и вызвать HasFlag только в том случае, если базовое значение флага отличное от нуля, как показано в следующем примере. * –

+0

Да, я знаю. Но ваш пример пишет 'true', что не очень хорошо - есть флаг ошибки ResponseTooBig', правильно? – vojta

1

Хотя это хорошая идея, чтобы фактически определить значение 0 в вашем перечислении, это очень плохая идея для того, чтобы представлять OK, поскольку 0 значения по умолчанию, и это единственное специальное целое число, которое неявно раскладывается в перечисление, так что он может ползать в легко:

MyStatus status = 0; 

Таким образом, фактическое определение значения 0 не представляет проблемы, но рекомендуется сделать это для представления None для Flags перечислений или значения Invalid для нормальных перечислений.

Также необходимо использовать перечисления Flags, когда члены могут быть объединены, но из вашего примера кажется, что они являются взаимоисключающими.

Итак, я бы сказал, что перечисление плохо спроектировано, потому что, поскольку оно есть, любой ответ имеет флаг OK, и это, безусловно, ошибка для перечисления Flags, и если вы не можете изменить определение, быть явным образом проверить, если статус равен OKResponse:

if (status == MyStatus.OKResponse) 
Смежные вопросы