在枚举中,对于值为None(0)的情况,HasFlags始终返回true。

36

这是枚举类型的定义:

[Flags]
enum Animals
{
    None = 0,
    Dog = 1,
    Cat = 2,
    Horse = 4,
    Zebra = 8,
}
现在,鉴于以下代码,请问为什么HasFlag方法会针对Animals.None值返回true?
Animals myAnimals = Animals.Dog | Animals.Horse;

var hasNone = myAnimals.HasFlag(Animals.None);    //true! Why?
var hasCat = myAnimals.HasFlag(Animals.Cat);      //false
var hasDog = myAnimals.HasFlag(Animals.Dog);      //true
var hasHorse = myAnimals.HasFlag(Animals.Horse);  //true
var hasZebra = myAnimals.HasFlag(Animals.Zebra);  //false
7个回答

50

HasFlag 的实际作用如下:

HasFlag = (GivenFlag & Value) == GivenFlag;

//"Anything" AND 0 == 0  --> always true

11

我自己以前也遇到过这个问题。这是在.NET Framework中设计的:

如果标志(flag)的基础值为零,则该方法返回true。如果不希望出现此行为,您可以使用Equals方法测试与零的相等性,并且仅在标志(flag)的基础值为非零时调用HasFlag,如以下示例所示。

您可以在此处了解更多信息。


进一步说,我实现的解决方案是通过调用 value.Equals(myEnum.Zero) 处理零边缘情况,然后使用 .HasFlag 处理其他所有情况。 - gcode

2
已经有很多答案解释了为什么会发生这种情况,所以我只想补充一点,为了得到你想要的结果,你可以不使用HasFlag,而是使用var hasNone = myAnimals == Animals.None
我个人非常讨厌扩展方法,但如果你真的希望能够只编写myOptionEnum.HasNoFlags(),那么可以将其放在Enum的扩展方法中。我建议在这种特殊情况下明确检查None值。

1

最终我移除了'None'元素。它是一个'神奇的值',并且会干扰到正确的Flags Enum操作(如HasFlag())。

如果没有值,请使用Nullable即Animals?(现在支持原始类型)

编辑:我需要一个非零的“默认”值(用于序列化对象),以避免使用Nullable(这会与业务逻辑冲突)。但我认为这仍然比使用“None = 0”更好。


枚举类型的默认值为零,因此最好将其保留在枚举中。 - Vladislav Borovikov
@VladislavBorovikov,将'None=0'打破了HasFlag()的逻辑。你可以像测试对象是否为空一样测试枚举是否为0。我所描述的方法是如果你想让HasFlag()每次都能正常工作的话。 - Peter L

0

好的,Enum.HasFlags 大致解析如下:

var hasNone = (myAnimals & Animals.None) == Animals.None

对于零值枚举字段,这将始终为真。


0

来自MSDN

HasFlag方法返回以下布尔表达式的结果。

thisInstance And flag = flag

0

这只是HasFlag方法的定义行为。来自MSDN文档

如果标志的基础值为零,则该方法返回true


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接