【发布时间】:2012-06-21 16:21:25
【问题描述】:
背景:按位枚举对于“更具可读性”的比较和检查很有用:即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
参考资料:
- What does the [Flags] Enum Attribute mean in C#?
- MSDN Enumeration Types
- MSDN FlagsAttribute
- Bitwise enum cast return value not expected
为了完整起见,我正在用@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
【问题讨论】:
-
因为这有点深奥,所以问题的重点是,即使我可以“安全”并使用按位移位,我认为使用操作的效率略低于只需声明值(并且 DWORD 语法比显式地相乘更容易)
-
您是说 VS2012 RC 中的行为不同于 VS 2010 吗?如果是,那么这可能是 VS2012 / C# 编译器错误。快向 MSFT 报告!