枚举定义中的加号运算符

时间:2012-02-15 21:39:50

标签: c# enums

我偶然发现在枚举定义中使用了加号(+)运算符,我很惊讶地看到随附的测试通过了。任何人都知道这可以记录在哪里?

public enum ApprovalItemState
{
    Enqueued = 1,
    Approved = 2,
    Denied = 4,
    Acknowledged = 8,
    ApprovalAcknowledged = ApprovalItemState.Approved + ApprovalItemState.Acknowledged,
    DenialAcknowledged = ApprovalItemState.Denied + ApprovalItemState.Acknowledged
}


[TestClass]
public class ApprovalItemStateTests
{
    [TestMethod]
    public void AreFlagsDeniedAndAcknowledged()
    {
        Assert.AreEqual(ApprovalItemState.DenialAcknowledged, ApprovalItemState.Denied | ApprovalItemState.Acknowledged);
    }

    [TestMethod]
    public void IsDenialAcknowledged()
    {
        Assert.IsTrue(Enum.IsDefined(typeof(ApprovalItemState), ApprovalItemState.Denied | ApprovalItemState.Acknowledged));
        Assert.AreEqual(ApprovalItemState.Denied | ApprovalItemState.Acknowledged, (ApprovalItemState)Enum.Parse(typeof(ApprovalItemState), "DenialAcknowledged"));
    }


    [TestMethod]
    public void IsNotDeniedAndApproved()
    {
        Assert.IsFalse(Enum.IsDefined(typeof(ApprovalItemState), ApprovalItemState.Approved | ApprovalItemState.Denied));
    }
}

6 个答案:

答案 0 :(得分:11)

里德的答案当然是正确的。我只是觉得我会添加一些有趣的琐事。首先,当你在里面枚举时,枚举的所有成员都在范围内。这是C#中唯一可以通过其非限定名称使用枚举成员的情况!

public enum ApprovalItemState 
{
    Enqueued = 1,
    Approved = 2,
    Denied = 4,
    Acknowledged = 8,
    ApprovalAcknowledged = Approved | Acknowledged,
    DenialAcknowledged =  Denied | Acknowledged 
} 

第二个琐事是C#编译器实际上允许enum算术涉及枚举中的其他枚举

enum E
{
    E1
}
enum F
{
    F1
}
enum G
{
    G1 = E.E1 + F.F1
}

通常情况下,这根本不合法;你不能在一起添加两个不同的枚举,你不能分配结果。编译器在枚举初始值设定项中放宽这些规则,以便您可以执行以下操作:

enum MyFlags
{
    MyReadOnly = FileFlags.ReadOnly,
    ...

答案 1 :(得分:10)

14.5中的C#语言规范声明:

  

以下运算符可用于枚举类型的值:==,!=,<,>,< =,> =(§7.10.5),二进制+(§7.8.4),二进制 - (§7.8.5),^,&,| (§7.11.2),〜(§7.7.4),++和 - (§7.6.9和§7.7.5)。

基本上,由于枚举在内部存储为Int32(这是默认值,除非您指定不同的存储类型),您可以像这样添加。

但是,使用|代替+来定义蒙版更为常见。此外,如果您要将此作为标志枚举使用,则通常会包含[Flags]

答案 2 :(得分:2)

来自the C# reference on enum

  

...每个枚举类型都有一个底层类型,除了char之外,它可以是任何整数类型。 枚举元素的默认基础类型是int ...

顺便说一下,使用|代替+来组合枚举标志值更具惯用性(并且更不容易出错)。例如,这个错误不会导致问题:

DenialAcknowledged =
    ApprovalItemState.Denied
    | ApprovalItemState.Acknowledged
    | ApprovalItemState.Denied

但是这个错误导致问题:

DenialAcknowledged =
    ApprovalItemState.Denied
    + ApprovalItemState.Acknowledged
    + ApprovalItemState.Denied

答案 3 :(得分:1)

Approved + Acknowledged只是一个常量,因此可以将其指定为枚举元素的值。 关于测试 - 它们起作用因为int值是“快乐的”,所以(a + b) == (a | b)

但是如果你改变了那样的话:

public enum ApprovalItemState
{
    Enqueued = 1,
    Approved = 2,
    Denied = 7,
    Acknowledged = 18,
    ApprovalAcknowledged = Approved + Acknowledged,
    DenialAcknowledged = Denied + Acknowledged
}

并且测试不会通过。

答案 4 :(得分:0)

这并不奇怪 - 枚举用整数类型表示。你也可以使用其他运算符,虽然如果你打算使用标志(这个例子正在做),最好使用[Flags]属性来定义它们,并且更好地更清楚地布局:

[Flags]
public enum ApprovalItemState
{
    Enqueued = 1 << 0,
    Approved = 1 << 1,
    Denied = 1 << 2,
    Acknowledged = 1 << 3,
    ApprovalAcknowledged = ApprovalItemState.Approved | ApprovalItemState.Acknowledged,
    DenialAcknowledged = ApprovalItemState.Denied | ApprovalItemState.Acknowledged
}

答案 5 :(得分:0)

我会为你分解其中一个。

DenialAcknowledged = ApprovalItemState.Denied + ApprovalItemState.Acknowledged
DenialAcknowledged = 4 + 8
DenialAcknowledged = 12

对于此测试:

[TestMethod]
public void AreFlagsDeniedAndAcknowledged()
{
    Assert.AreEqual(ApprovalItemState.DenialAcknowledged, ApprovalItemState.Denied | ApprovalItemState.Acknowledged);
}

您正在检查:

ApprovalItemState.DenialAcknowledged == ApprovalItemState.Denied | ApprovalItemState.Acknowledged
12 == 4 | 8
12 == 0100 | 1000 //bitwise operation 
12 == 1100
12 == 12 //convert from binary to decimal

这就是测试通过的原因。通过查看代码并不简单。