测试按位枚举值

时间:2011-05-24 04:21:09

标签: c# enums comparison bit-manipulation bit

之前我没有真正使用过按位枚举,我只是想确保我的测试是正确的。我最感兴趣的是测试值None和All。我们从使用此枚举的Web服务接收数据,以对某些数据进行分类。鉴于此,我假设nether None和All将与任何其他值组合。

给出以下按位枚举定义;

[System.FlagsAttribute()]
public enum TrainingComponentTypes : int
    {
        None = 0,
        AccreditedCourse = 1,
        Qualification = 2,
        Unit = 4,
        SkillSet = 8,
        UnitContextualisation = 16,
        TrainingPackage = 32,
        AccreditedCourseModule = 64,
        All = 127,
    }

我在this MSDN site上阅读了关于FlagAttributes的以下引用;

  

使用None作为标志的名称   枚举常量,其值为   零。您不能使用None   按位AND枚举常量   测试标志的操作因为   结果总是为零。然而,   你可以执行逻辑,而不是   按位,比较   数值和无枚举   常量判断是否有任何位   在数值中设置。

此实例中的逻辑比较是否指向枚举的正常相等性测试? 例如;

TrainingComponentTypes tct = TrainingComponentTypes.None; 
if (tct == TrainingComponentTypes.None) 
{ ... }

对于按位比较,我正在执行以下操作;

 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");

最后,在测试所有内容时,我尝试了逻辑和按位比较,并且它们都返回相同的内容。我应该在这里使用一个吗?例如;

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");

总而言之,我想知道关于Bitwise枚举的以下内容;

  1. 我的理解是合乎逻辑的 比较正确给出我的例子 以上?
  2. 我的表现方式 按位比较正确吗?
  3. 处理“全部”的正确方法是什么 值(按位或逻辑)。我不确定我们是否会收到一个值,其中All与其他TrainingComponentTypes结合使用。我不明白为什么会这样,但是,你永远都不知道?
  4. 我是正确的假设切换 陈述基本上不应该 用于按位枚举(没有给出 似乎是一个特例和 需要逻辑比较)?
  5. 谢谢, 克里斯

7 个答案:

答案 0 :(得分:17)

简答:是的:)

长:

1)所有操作都是在flags变量的整数值上执行的,所以你可以用这个来考虑它们。

2)是的。

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

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

对于这部分:

  

我不确定我们是否会收到All与其他TrainingComponentTypes合并的值。

我不确定你是否完全理解枚举是如何运作的。

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

正如您所看到的,All只是所有这些值的按位|。您不能将任何其他TraningComponentTypes与All结合使用,因为All已经包含它们!另外,如果你将它们与|自己组合在一起,它与直接使用All完全相同(因此,当你在枚举中定义它时,All只是一种方便)。

4)你可以使用它来检查None或All,但不能用于其他值。

值得注意的是,Enum上有一种方便的方法可以为您执行这些检查:Enum.HasFlag

答案 1 :(得分:8)

  

鉴于上面的例子,我对逻辑比较的理解是否正确?

是的,在这种情况下,逻辑意味着运营商的平等和不平等。

  

我执行按位比较的方式是否正确?

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

tct.HasFlag(TrainingComponentTypes.Qualification)

而不是:

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

处理“全部”值(按位或逻辑)的正确方法是什么。我不确定我们是否会收到一个值,其中All与其他TrainingComponentTypes结合使用。我不明白为什么会这样,但是,你永远不知道?

我认为最好将All本身中的enum定义为其所有部分的按位OR。但是你会看到人们都是这样做的。

  

我是否正确地假设switch语句基本上不应该用于按位枚举(假设没有看起来是特殊情况并且需要逻辑比较)?

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

答案 2 :(得分:1)

  1. 可以使用逻辑和按位。用法取决于是否所有位都设置或仅是您定义的所有值的按位OR。

  2. 是的,但不是因为None。交换机比较单个值,而比特字段显然可以有多个值。

  3. 正如其他人所说,Enum包含HasFlag()

答案 3 :(得分:0)

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

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

3 - 我不确定你是否需要所有价值。我会删除它。

4 - 是的,switch语句通常对Flags枚举没有意义。

答案 4 :(得分:0)

  

“3.处理”全部“值(按位或逻辑)的正确方法是什么。我不确定我们是否会收到一个值,其中All与其他TrainingComponentTypes结合使用。我看不清楚为什么我们会,但“

您似乎误解了按位枚举值的工作原理。 'All'总是与其他值组合,实际上它是所有值的组合。查看枚举的二进制值:

无= 0,
AccreditedCourse = 1,
资格= 10,
单位= 100,
SkillSet = 1000,
UnitContextualisation = 10000,
TrainingPackage = 100000,
AccreditedCourseModule = 1000000,
全部= 1111111

这有助于您理解吗?

答案 5 :(得分:0)

1& 2看起来很好

3。 所有已定义的内容都不能与任何内容组合而不会丢失数据。如果“all”是您希望从服务器接收的实际值,则应该将其更改为128。

否则它是一个便利值,您可以用来测试是否设置了任何值...除非您的标志值作为二进制数据发送并打包在可能包含其他数据的字节中,否则您不应该需要它。 / p>

4。 如果/当你有多个标志的值时,可以使用switch语句但是效果不好,如果有有效标志组合的小子集它们仍然有用。

答案 6 :(得分:0)

在模型中 as_enum :shifts, { day_shift: 0, 晚班:1, 夜班:2, }, 访问器: :bitwise

在视图中 Model.enum_collection(:shifts)