关于c#:测试按位枚举值

Testing for bitwise Enum values

我以前没有真正使用过位枚举,我只是想确保我的测试是正确的。我最感兴趣的是测试值none和all。我们从Web服务接收数据,该服务使用此枚举对某些数据片段进行分类。考虑到这一点,我假设下一个或全部都不会与任何其他价值结合起来。

给出以下按位枚举定义;

1
2
3
4
5
6
7
8
9
10
11
12
13
[System.FlagsAttribute()]
public enum TrainingComponentTypes : int
    {
        None = 0,
        AccreditedCourse = 1,
        Qualification = 2,
        Unit = 4,
        SkillSet = 8,
        UnitContextualisation = 16,
        TrainingPackage = 32,
        AccreditedCourseModule = 64,
        All = 127,
    }

我在这个msdn网站上阅读了以下关于flagattributes的引述;

Use None as the name of the flag
enumerated constant whose value is
zero. You cannot use the None
enumerated constant in a bitwise AND
operation to test for a flag because
the result is always zero. However,
you can perform a logical, not a
bitwise, comparison between the
numeric value and the None enumerated
constant to determine whether any bits
in the numeric value are set.

此实例中的逻辑比较是否指枚举的普通相等测试?例如;

1
2
3
TrainingComponentTypes tct = TrainingComponentTypes.None;
if (tct == TrainingComponentTypes.None)
{ ... }

为了进行逐位比较,我将执行以下操作:

1
2
3
4
 TrainingComponentTypes tct = TrainingComponentTypes.AccreditedCourse | TrainingComponentTypes.Qualification | TrainingComponentTypes.TrainingPackage;
 Assert.IsTrue((tct & TrainingComponentTypes.AccreditedCourse) == TrainingComponentTypes.AccreditedCourse,"Expected AccreditedCourse as part the enum");

 Assert.IsFalse((tct & TrainingComponentTypes.SkillSet) == TrainingComponentTypes.SkillSet,"Found unexpected SkillSet as part the enum");

最后,当测试所有内容时,我尝试了逻辑和位比较,它们都返回相同的结果。我应该在这里用一个而不是另一个吗?例如;

1
2
3
4
5
6
7
TrainingComponentTypes tct = TrainingComponentTypes.All;

Assert.IsTrue((tct & TrainingComponentTypes.All) == TrainingComponentTypes.All,"Expected All as part the enum");
Assert.IsTrue((tct) == TrainingComponentTypes.All,"Expected All as part the enum");
// The follow also pass the assertion for a value of All
Assert.IsTrue((tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification,"Expected Qualification as part the enum");
Assert.IsTrue((tct & TrainingComponentTypes.TrainingPackage) == TrainingComponentTypes.TrainingPackage,"Expected TrainingPackage as part the enum");

总之,我想知道下面关于位枚举的内容;

  • 我对逻辑的理解举个例子比较正确上面?
  • 是我表演的方式吗按位比较正确吗?
  • 处理"全部"的正确方法是什么值(按位或逻辑)。我不确定我们是否曾经收到过一个值,其中所有值都与其他培训组件类型相结合。我不明白我们为什么要这样做,但你永远不知道?
  • 我假设那个开关是对的吗声明基本上不应该是用于位枚举(给定为无似乎是个特例需要逻辑比较吗?
  • 谢谢,克里斯


    简短回答:是:)

    比较长的:

    1)所有操作都是在flags变量的整数值上执行的,因此您可以从这个角度来考虑这些操作。

    2)是的。

    3)任一工程。但是,值得注意的是,如果有人将一个无效的值推入一个变量,那么== TrainingComponentTypes.All版本将失败。例如:

    1
    2
    3
    var badValue = (TrainingComponentTypes)128 | TrainingComponentTypes.All;
    // now badValue != TrainingComponentTypes.All
    // but (badValue & TrainingComponentTypes.All) == TrainingComponentTypes.All

    对于这一部分:

    I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes.

    我不确定您是否完全理解枚举是如何在封面下工作的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    The value of All is:
        127 = 1111111 (binary)

    The other values are:
        AccreditedCourse       = 0000001
        Qualification          = 0000010
        Unit                   = 0000100
        SkillSet               = 0001000
        UnitContextualisation  = 0010000
        TrainingPackage        = 0100000
        AccreditedCourseModule = 1000000

    如您所见,所有这些值加在一起只是按位的|。您不能将任何其他TraningComponentType与All组合,因为All已经包含了它们!另外,如果您将它们与|本身结合在一起,这与直接使用all完全相同(因此,当您在枚举中定义它时,all只是一种便利)。

    4)您可以使用它来检查"无"或"全部",但不能检查其他值。

    值得注意的是,枚举上有一个方便的方法可以为您执行这些检查:enum.hasFlag。


    Is my understanding of a logical comparison correct given my example above?

    是的,在这个上下文中,逻辑意味着相等和不相等运算符。

    Is the way I am performing a bitwise comparison correct?

    是的,但有一个更简单的方法:Enum.HasFlag。例如:

    1
    tct.HasFlag(TrainingComponentTypes.Qualification)

    而不是:

    1
    (tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification

    What is the right way to handle the"All" value (bitwise or logical). I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes. I can't see why we would, but then, you never know?

    我认为最好把enum中的All定义为位或其所有部分。但你会看到人们都这样做。

    Am I right in assuming that switch statements basically shouldn't be used for bitwise enums (given none is appears to be a special case and requires a logical comparison)?

    不,一点也不。请随意使用它们是switch声明。case值必须是常量,但它们可以是表达式,并测试是否相等。如果您做了一些愚蠢的事情,比如尝试使用相同的case值两次,编译器会告诉您。


  • 对。

  • 是的

  • 可以同时使用逻辑和位。用法取决于是否所有的位都被设置,或者只是按位还是按您定义的所有值。

  • 是的,但不是因为None。开关比较单个值,而位字段显然可以有多个值。

  • 正如其他人所指出的,枚举包含hasFlag()。


    1&2看起来不错

    三。正如您所定义的那样,在不丢失数据的情况下不能与任何内容组合。如果"all"是您期望从服务器接收的实际值,那么您可能应该将其更改为128。

    否则,它是一个方便的值,可以用来测试是否设置了任何值…除非将标志值作为二进制数据发送并打包到可能包含其他数据的字节中,否则不需要这样做。

    4。可以使用switch语句,但如果/当您有多个标志的值时,这些语句将无法正常工作;如果存在有效标志组合的小子集,则它们仍然有用。


    "3.What is the right way to handle the"All" value (bitwise or logical). I am not sure if we'd ever receive a value where All was combined with other TrainingComponentTypes. I can't see why we would, but"

    似乎您误解了按位枚举值的工作方式。""all"总是与其他值组合在一起,实际上它是所有值的组合。查看枚举的二进制值:

    NO=0,认可的课程=1,资格=10,单位=100,技能集=1000,统一上下文=10000,培训包=100000,认可的课程表=1000000,全部=1111111

    这有助于你理解吗?


    1和2-是的,但是有一种方法可以让阅读变得更容易:

    1
    2
    TrainingComponentTypes tct = TrainingComponentTypes.AccreditedCourse | TrainingComponentTypes.Qualification;
    Assert.IsTrue(tct.HasFlag(TrainingComponentTypes.AccreditedCourse),"Expected AccreditedCourse as part the enum");

    3-我不确定你是否需要所有的价值。我会把它取下来。

    是的,switch语句对于标志枚举通常没有意义。