C# 为什么我永远不能在标志枚举中使用0

C# 为什么我永远不能在标志枚举中使用0,c#,enums,flags,C#,Enums,Flags,可能重复: 为什么我永远不能在标志枚举中使用0?我已经读了很多遍了,现在想 知道原因:)因为标志枚举是位集合或选项集 0值将是所有集合的一部分,或不属于任何集合。这就是行不通 因为通常使用以下标志: var myFlagEnum = MyEnum.Foo | MyEnum.Bar | MyEnum.Bat; // ... snip ... if (myFlagEnum & MyEnum.Foo == MyEnum.Foo) { ... do something ... };

可能重复:

为什么我永远不能在标志枚举中使用0?我已经读了很多遍了,现在想
知道原因:)

因为标志枚举是位集合或选项集


0
值将是所有集合的一部分,或不属于任何集合。这就是行不通

因为通常使用以下标志:

var myFlagEnum = MyEnum.Foo | MyEnum.Bar | MyEnum.Bat;

// ...  snip ...

if (myFlagEnum & MyEnum.Foo == MyEnum.Foo) { ...  do something ... };

如果MyEnum.Foo为零,则上述操作将不起作用(对于所有情况,它将返回true)。然而,如果它是1,那么它将工作。

标记枚举的使用方式如下:

Flag flags = Flag.First | Flag.Next | Flag.Last;
enum Flag {First = 1, Next = 2, Last = 4};
然后,您应该这样定义您的标志:

Flag flags = Flag.First | Flag.Next | Flag.Last;
enum Flag {First = 1, Next = 2, Last = 4};
这样,您可以查看是否使用了标志,例如:

if (flags & Flag.First <> 0) Console.WriteLine("First is set");
if (flags & Flag.Next <> 0) Console.WriteLine("Next is set");
if (flags & Flag.Last <> 0) Console.WriteLine("Last is set");
if(flags&Flag.First 0)Console.WriteLine(“设置了First”);
if(flags&Flag.Next 0)Console.WriteLine(“设置了Next”);
if(flags&Flag.Last 0)Console.WriteLine(“设置了Last”);
这就是为什么只能使用2的幂的值,例如1,2,4,8,16,32,64128

如果标志为0,则视为空白


我希望这将增加您对标志枚举的理解。

尽管零表示未设置任何位,但为0指定一个命名常量通常非常有用

设置标志字时,我定义位的名称,以便它们都表示非默认值。也就是说,枚举值始终初始化为零,从而“关闭”位字段表示的所有选项

这为枚举提供了向前兼容性,因此任何创建新值的人都知道,如果以后向位字段添加更多标志,任何零位都将是“安全”的

类似地,组合多个标志以生成新的常量名称非常有用,这使代码更具可读性


这样做的危险性(以及您引用规则的原因)在于,您必须注意单个位值(标志)与表示位组或位组合的值之间的差异。

我真的不认为有问题

enum Where {Nowhere=0x00, Left=0x01, Right=0x02, Both=Left|Right};
Where thevalue = Where.Both;
bool result = (thevalue&Where.Nowhere)==Where.Nowhere;
结果当然是真的!你期待什么?来,想想这个

bool result1 = (thevalue&Where.Left)==Where.Left;
bool result2 = (thevalue&Where.Right)==Where.Right;
bool result3 = (thevalue&Where.Both)==Where.Both;
这些都是真的!为什么
无处可去
是特别的?0没有什么特别之处

为什么我永远不能在标志枚举中使用0

这个问题是建立在一个错误的假设上的。在标志枚举中应始终使用零。它应始终设置为“无”

除了表示“未设置任何标志”之外,您不应将其用于任何其他用途

为什么不呢


因为如果零不是“无”的意思,它会变得非常混乱。人们有合理的期望,
((e&e.X)=e.X)
表示“X标志是否已设置?”但如果X为零,则该表达式将始终为真,即使在逻辑上该标志未“设置”。

标志枚举假定其每一个值都表示存在一个选项,并在枚举的一个位中进行编码。因此,如果存在特定选项(或为true),则枚举值中的等效位设置为(1),否则不设置为(0)

因此,枚举的每个字段都是一个仅设置了一位的值。如果没有任何选项存在或为true,则组合枚举的值为零,这意味着没有设置任何位。因此,标志枚举中唯一的零字段应该是表示未设置、为true或未选择任何选项的字段

例如,假设我们有一个标志枚举,它对表单元格中存在的边框进行编码

public enum BorderType
{
    None   = 0x00, // 00000000 in binary
    Top    = 0x01, // 00000001 in binary
    Left   = 0x02, // 00000010 in binary
    Right  = 0x04, // 00000100 in binary
    Bottom = 0x08  // 00001000 in binary
}
如果要显示单元格具有上下边框,则应使用值

 Cell.Border = BorderType.Top | BorderType.Bottom; // 0x01 | 0x08 = 0x09 = 00001001 in binary
 Cell.Border = BorderType.None; // 0x00 = 00000000 in binary
如果要显示单元格没有边框,则应使用值

 Cell.Border = BorderType.Top | BorderType.Bottom; // 0x01 | 0x08 = 0x09 = 00001001 in binary
 Cell.Border = BorderType.None; // 0x00 = 00000000 in binary

因此,决不能将零用作标志枚举中选项的值,但是您应该始终使用零作为值,这意味着没有设置任何标志。

我想知道您在哪里读到它,以及为什么这么说……除了表示未设置的值之外,您不应该使用它。您应该只将它用于
none
选项。@ChrisShain不,它不是。把事实弄清楚。1和2是0。一个显式的
None
命名值有时是有用的。为了阐述@Henk的优秀答案:AnyNumber和0将始终等于0,用任何数字对0进行ORing将对数字产生影响(将始终等于其自身)我相信您打算使用位运算符
&
而不是逻辑AND运算符
&
。好的,对不起,不应该在窗口中编码。从技术上讲,您不必使用2的幂。例如,值1、10、100也可以工作(因为它们的位不重叠)。但是没有理由这样做。A)OP是关于标志枚举的。您只看到类似于标志的行为,因为枚举的默认实现是递增整数的赋值,最多可使用4个条目(并且仅当第四个条目是第二个和第三个条目的并集时)。尝试添加第五个值。B) 无处是特别的,因为
Nowhere&left==Nowhere
,而
left&right==both
。不过,你知道,这没什么区别。关于
的工作原理,您仍然是错误的。查找它,或者在您自己的编译器上测试它<代码>左和右
实际上是
0
。老实说,问题是你把两者都定义为都=左|右,而不是都=无处|左|右。因此,当value=Where.Both but(thevalue&Where.Nowhere)==Where.Nowhere返回true时,它就无法使用此枚举表示多个选择。如果从0x01开始,则不会发生这种情况。也许你应该用一个不同的例子来思考,而不是你使用的例子。请在一周中的几天内进行更改。@MrLister将它们定义为标志是什么问题?如果您这样做,您可以使用同一枚举的值表示多天。在这种情况下,您的场景与上面相同。星期日=位0,星期一=位1等。值“从不”可以表示为