编辑:似乎大多数人误解了我的问题。
我知道枚举是如何运作的,我知道二进制。我想知道为什么带有[Flags]属性的枚举的设计方式就是这样。
原帖:
这可能是重复的,但我没有找到任何其他帖子,所以这里就是。
我打赌它背后有一些很好的理由,我发现它有点容易出错。
[Flag]
public enum Flagged
{
One, // 0
Two, // 1
Three, // 2
Four, // 3
}
Flagged f; // Defaults to Flagged.One = 0
f = Flagged.Four;
(f & Flagged.One) != 0; // Sure.. One defaults to 0
(f & Flagged.Two) != 0; // 3 & 1 == 1
(f & Flagged.Three) != 0; // 3 & 2 == 2
如果它做了这样的事情会不会更有意义?
[Flag]
public enum Flagged
{
One = 1 << 0, // 1
Two = 1 << 1, // 2
Three = 1 << 2, // 4
Four = 1 << 3, // 8
}
Flagged f; // Defaults to 0
f = Flagged.Four;
(f & Flagged.One) != 0; // 8 & 1 == 0
(f & Flagged.Two) != 0; // 8 & 2 == 0
(f & Flagged.Three) != 0; // 8 & 4 == 0
(f & Flagged.Four) != 0; // 8 & 8 == 8
当然..我不太确定它应该如何处理像这样的自定义标志
[Flag]
public enum Flagged
{
One, // 1
Two, // 2
LessThanThree = One | Two,
Three, // 4? start from Two?
LessThanFour = Three | LessThanThree,
Three, // 8? start from Three?
}
规范提供了一些指导
以2的幂为单位定义枚举常量,即1,2,4,8等。这意味着组合枚举常量中的各个标志不重叠。
但这应该是自动完成的,因为我打赌你永远不会想要我的第一个例子。请赐教:))
答案 0 :(得分:12)
Flags
属性仅用于将值格式化为多个值。位操作适用于具有或不具有该属性的基础类型。
答案 1 :(得分:7)
除非明确给出其他值,否则枚举的第一项为零。通常最佳做法是为标志枚举设置零值,因为它为零值提供了语义含义,例如“无标志”或“关闭”。这可能有助于维护代码,因为它可能意味着代码意图(尽管注释也实现了这一点)。
除此之外,您和您的设计是否取决于您是否需要零值。
由于标志枚举仍然只是枚举(FlagsAttribute
仅指示调试器将值解释为其他值的组合),枚举中的下一个值总是比前一个值多一个。因此,您应该明确指定位值,因为您可能希望将组合表示为其他值的按位或。
也就是说,想象一个标志枚举的语法,要求所有按位组合放在枚举定义的末尾或以某种方式标记,这样编译器就知道如何处理其他所有内容,这是不合理的。 / p>
例如(假设flags
关键字并且我们在北半球),
flags enum MyFlags
{
January,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December,
Winter = January | February | March
Spring = April | May | June
Summer = July | August | September
Autumn = October | November | December
}
使用这种语法,编译器可以自己创建0值,并自动为其他值分配标志。
答案 2 :(得分:6)
属性是[Flags]而不是[Flag],并没有什么神奇之处。它似乎唯一影响的是ToString方法。指定[标志]时,值以逗号分隔。由您指定值以使其在位字段中有效。
答案 3 :(得分:4)
注释的C#3规范中没有任何内容。我认为可能是带注释的C#4规范中的东西 - 我不确定。 (我想我自己开始编写这样的注释,但后来将其删除了。)
对于简单的情况很好,但是一旦你开始添加额外的标志,它就会有点棘手:
[Flags]
enum Features
{
Frobbing, // 1
Blogging, // 2
Widgeting, // 4
BloggingAndWidgeting = Frobbing | Blogging, // 6
Mindnumbing // ?
}
Mindnumbing应该有什么价值?下一个没用过的位?如果你设置一个固定的整数值怎么样?
我同意这是一种痛苦。也许可以制定一些合理的规则......但我想知道复杂性与价值平衡是否真的有效。
答案 4 :(得分:2)
简单地说,Flags
是一个属性。它在创建枚举之后才会应用,因此不会更改分配给枚举的值。
话虽如此,MSDN页面Designing Flags Enumerations说明了这一点:
对标志使用2的幂 枚举的值,所以它们可以 使用按位OR自由组合 操作
重要提示:如果您不使用2或2的权力 两个幂的组合,按位 操作无法按预期工作。
同样,FlagsAttribute
的页面显示
定义幂中的枚举常量 两个,即1,2,4,8等 上。这意味着中的各个标志 组合枚举常数不会 重叠。
答案 5 :(得分:0)
在C中,可以(ab)使用预处理器自动生成2次幂枚举。如果有一个宏make_things扩展为“make_thing(flag1)make_thing(flag2)make_thing(flag3)”等,则可以多次调用该宏,并使用不同的make_thing定义,以实现2的幂国旗名称序列以及其他一些好东西。
例如,首先将make_thing(x)定义为“LINEAR_ENUM _ ## x”(包括逗号),然后使用enum语句生成枚举列表(包括在make_things宏之外的LINEAR_NUM_ITEMS)。然后创建另一个枚举,这次将make_thing(x)定义为“FLAG_ENUM _ ## x = 1&lt;
相当漂亮的一些事情可以这样做,旗帜和线性值自动保持同步;代码可以做很好的事情,比如“if(thingie [LINEAR_ENUM_foo] thing_errors | = FLAG_ENUM_foo;”(同时使用线性和标志值)。不幸的是,我知道在C#或VB.net中无法做任何远程类似的事情。