Предпосылки: Побитовые перечисления полезны для «более удобочитаемого» сравнения и проверки: т.е. OpenFile(write | append)
.
Я видел несколько способов объявления побитовых перечислений в C #, но в последнее время один из распространенных шаблонов, похоже, больше не возвращает уникальные значения, и мне было интересно, объявляю ли я это неправильно или что-то изменилось. Я говорю о стиле «DWORD» (шестнадцатеричный?) (Показан ниже), который при перечислении в VS2012 RC дает значения как 1, 2, 3, 4 ... вместо ожидаемого побитового удвоения.
Может ли кто-нибудь еще воспроизвести это? Я отправляю код, который использовал для проверки, вместе с выводом на консоль; странное поведение происходит с ComparisonsDword
, как вы можете видеть по выходным данным для «Перечисление флагов, явные значения с DWORD».
Без флагов, обычное перечисление
/// <summary>
/// How to compare filter values; no underlying type declared, not flag
/// </summary>
public enum ComparisonsNotInt {
[Description("x")]
None
,
[Description("!=")]
NotEqual
,
[Description("=")]
Equal
,
[Description(">")]
GreaterThan
,
[Description("<")]
LessThan
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="LessThan"/>
/// </summary>
[Description("<=")]
LessThanOrEqual = (Equal | LessThan)
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="GreaterThan"/>
/// </summary>
[Description(">=")]
GreaterThanOrEqual = (Equal | GreaterThan)
}//-- enum ComparisonsNotFlag
Без флагов, базовый тип = int
/// <summary>
/// How to compare filter values, not flag but underlying type declared
/// </summary>
public enum ComparisonsNotFlag : int {
[Description("x")]
None
,
[Description("!=")]
NotEqual
,
[Description("=")]
Equal
,
[Description(">")]
GreaterThan
,
[Description("<")]
LessThan
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="LessThan"/>
/// </summary>
[Description("<=")]
LessThanOrEqual = (Equal | LessThan)
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="GreaterThan"/>
/// </summary>
[Description(">=")]
GreaterThanOrEqual = (Equal | GreaterThan)
}//-- enum ComparisonsNotFlag
Флаг, неявное значение
/// <summary>
/// How to compare filter values; values default to whatever .NET decides
/// </summary>
[Flags]
public enum ComparisonsImplicit : int {
[Description("x")]
None
,
[Description("!=")]
NotEqual
,
[Description("=")]
Equal
,
[Description(">")]
GreaterThan
,
[Description("<")]
LessThan
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="LessThan"/>
/// </summary>
[Description("<=")]
LessThanOrEqual = (Equal | LessThan)
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="GreaterThan"/>
/// </summary>
[Description(">=")]
GreaterThanOrEqual = (Equal | GreaterThan)
}//-- enum ComparisonsImplicit
Флаг, явное значение
/// <summary>
/// How to compare filter values; values explicitly defined with doubled numbers
/// </summary>
[Flags]
public enum ComparisonsExplicit : int {
[Description("x")]
None = 0
,
[Description("!=")]
NotEqual = 1
,
[Description("=")]
Equal = 2
,
[Description(">")]
GreaterThan = 4
,
[Description("<")]
LessThan = 8
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="LessThan"/>
/// </summary>
[Description("<=")]
LessThanOrEqual = (Equal | LessThan)
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="GreaterThan"/>
/// </summary>
[Description(">=")]
GreaterThanOrEqual = (Equal | GreaterThan)
}//-- enum ComparisonsExplicit
Флаг, явное значение с использованием стиля DWORD Примечание: это то, что неправильно предоставляет уникальные значения, поэтому такие комбинации, как GreaterThanOrEqual
, не работают.
/// <summary>
/// How to compare filter values; values explicitly defined with DWORD style
/// </summary>
[Flags]
public enum ComparisonsDword : int {
[Description("x")]
None = 0x0
,
[Description("!=")]
NotEqual = 0x1
,
[Description("=")]
Equal = 0x2
,
[Description(">")]
GreaterThan = 0x3
,
[Description("<")]
LessThan = 0x4
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="LessThan"/>
/// </summary>
[Description("<=")]
LessThanOrEqual = (Equal | LessThan)
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="GreaterThan"/>
/// </summary>
[Description(">=")]
GreaterThanOrEqual = (Equal | GreaterThan)
}//-- enum ComparisonsDword
Флаг, явное значение с использованием стиля DWORD Примечание: также недопустимые значения, просто проверяется, влияет ли базовый тип на проблему.
/// <summary>
/// How to compare filter values; values explicitly defined with DWORD style
/// </summary>
[Flags]
public enum ComparisonsDwordNotInt {
[Description("x")]
None = 0x0
,
[Description("!=")]
NotEqual = 0x1
,
[Description("=")]
Equal = 0x2
,
[Description(">")]
GreaterThan = 0x3
,
[Description("<")]
LessThan = 0x4
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="LessThan"/>
/// </summary>
[Description("<=")]
LessThanOrEqual = (Equal | LessThan)
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="GreaterThan"/>
/// </summary>
[Description(">=")]
GreaterThanOrEqual = (Equal | GreaterThan)
}//-- enum ComparisonsDword
Флаг, явное значение с использованием стиля сдвига битов
/// <summary>
/// How to compare filter values; values explicitly set using shorthand of bitwise shifting
/// </summary>
[Flags]
public enum ComparisonsBitshift : int {
[Description("x")]
None = 0
,
[Description("!=")]
NotEqual = 1 << 0
,
[Description("=")]
Equal = 1 << 1
,
[Description(">")]
GreaterThan = 1 << 2
,
[Description("<")]
LessThan = 1 << 3
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="LessThan"/>
/// </summary>
[Description("<=")]
LessThanOrEqual = (Equal | LessThan)
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="GreaterThan"/>
/// </summary>
[Description(">=")]
GreaterThanOrEqual = (Equal | GreaterThan)
}//-- enum ComparisonsBitshift
Вывод из перечисления:
Plain enum ----
Enum = None , Descr = x, Value = 0
Enum = NotEqual , Descr = !=, Value = 1
Enum = Equal , Descr = =, Value = 2
Enum = GreaterThan , Descr = >, Value = 3
Enum = GreaterThan , Descr = >, Value = 3 // bad: should be GTE
Enum = LessThan , Descr = <, Value = 4
Enum = LessThanOrEqual , Descr = <=, Value = 6
Plain enum, underlying int ----
Enum = None , Descr = x, Value = 0
Enum = NotEqual , Descr = !=, Value = 1
Enum = Equal , Descr = =, Value = 2
Enum = GreaterThan , Descr = >, Value = 3
Enum = GreaterThan , Descr = >, Value = 3 // bad: should be GTE
Enum = LessThan , Descr = <, Value = 4
Enum = LessThanOrEqual , Descr = <=, Value = 6
Flag enum, implicit values ----
Enum = None , Descr = x, Value = 0
Enum = NotEqual , Descr = !=, Value = 1
Enum = Equal , Descr = =, Value = 2
Enum = GreaterThanOrEqual, Descr = >=, Value = 3 // bad: should be GT
Enum = GreaterThanOrEqual, Descr = >=, Value = 3
Enum = LessThan , Descr = <, Value = 4
Enum = LessThanOrEqual , Descr = <=, Value = 6
Flag enum, explicit values ----
Enum = None , Descr = x, Value = 0
Enum = NotEqual , Descr = !=, Value = 1
Enum = Equal , Descr = =, Value = 2
Enum = GreaterThan , Descr = >, Value = 4
Enum = GreaterThanOrEqual, Descr = >=, Value = 6
Enum = LessThan , Descr = <, Value = 8
Enum = LessThanOrEqual , Descr = <=, Value = 10
Flag enum, explicit values with DWORD ---- // all of these are weirdly unexpected
Enum = None , Descr = x, Value = 0
Enum = NotEqual , Descr = !=, Value = 1
Enum = Equal , Descr = =, Value = 2
Enum = GreaterThanOrEqual, Descr = >=, Value = 3
Enum = GreaterThanOrEqual, Descr = >=, Value = 3
Enum = LessThan , Descr = <, Value = 4
Enum = LessThanOrEqual , Descr = <=, Value = 6
Flag enum, explicit values with DWORD, not underlying int ----
Enum = None , Descr = x, Value = 0
Enum = NotEqual , Descr = !=, Value = 1
Enum = Equal , Descr = =, Value = 2
Enum = GreaterThanOrEqual, Descr = >=, Value = 3
Enum = GreaterThanOrEqual, Descr = >=, Value = 3
Enum = LessThan , Descr = <, Value = 4
Enum = LessThanOrEqual , Descr = <=, Value = 6
Flag enum, explicit values with bitshifting ----
Enum = None , Descr = x, Value = 0
Enum = NotEqual , Descr = !=, Value = 1
Enum = Equal , Descr = =, Value = 2
Enum = GreaterThan , Descr = >, Value = 4
Enum = GreaterThanOrEqual, Descr = >=, Value = 6
Enum = LessThan , Descr = <, Value = 8
Enum = LessThanOrEqual , Descr = <=, Value = 10
Ссылки:
- Что означает атрибут Enum [Flags] в C #?
- Типы перечисления MSDN
- MSDN FlagsAttribute
- Не ожидается возвращаемое значение побитового приведения перечисления
Для полноты картины я изменяю свой исходный вопрос с правильным использованием из ответа @kirk-woll
Исправленный синтаксис DWORD
/// <summary>
/// How to compare filter values; values explicitly defined with *correct* DWORD style
/// </summary>
[Flags]
public enum ComparisonsDwordCorrectlyDefined {
[Description("x")]
None = 0x0
,
[Description("!=")]
NotEqual = 0x1
,
[Description("=")]
Equal = 0x2
,
[Description(">")]
GreaterThan = 0x4
,
[Description("<")]
LessThan = 0x8
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="LessThan"/>
/// </summary>
[Description("<=")]
LessThanOrEqual = (Equal | LessThan)
,
/// <summary>
/// Combination of <see cref="Equal"/> and <see cref="GreaterThan"/>
/// </summary>
[Description(">=")]
GreaterThanOrEqual = (Equal | GreaterThan)
}//-- enum ComparisonsDwordCorrectlyDefined
Вывод из перечисления
Flag enum, explicit values with correct DWORD ----
Enum = None , Descr = x, Value = 0
Enum = NotEqual , Descr = !=, Value = 1
Enum = Equal , Descr = =, Value = 2
Enum = GreaterThan , Descr = >, Value = 4
Enum = GreaterThanOrEqual, Descr = >=, Value = 6
Enum = LessThan , Descr = <, Value = 8
Enum = LessThanOrEqual , Descr = <=, Value = 10