枚举定义中的加号运算符
本文关键字:运算符 定义 枚举 | 更新日期: 2023-09-27 18:24:40
我今天偶然发现了枚举定义中加号(+(运算符的使用,我很惊讶地看到随附的测试通过了。 有人知道这可能在哪里记录吗?
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));
}
}
里德的回答当然是正确的。我只是想添加一些有趣的琐事。 首先,当您在枚举内时,枚举的所有成员都在范围内。这是 C# 中唯一可以通过枚举成员的非限定名称使用枚举成员的情况!
public enum ApprovalItemState
{
Enqueued = 1,
Approved = 2,
Denied = 4,
Acknowledged = 8,
ApprovalAcknowledged = Approved | Acknowledged,
DenialAcknowledged = Denied | Acknowledged
}
第二个琐事点是,C# 编译器实际上允许枚举算术涉及枚举内的其他枚举!
enum E
{
E1
}
enum F
{
F1
}
enum G
{
G1 = E.E1 + F.F1
}
通常这根本不合法;你不能将两个不同的枚举加在一起,也不能分配结果。编译器在枚举初始值设定项中放宽这些规则,以便您可以执行以下操作:
enum MyFlags
{
MyReadOnly = FileFlags.ReadOnly,
...
C# 语言规范在 14.5 中指出:
以下运算符可用于枚举类型的值:==、!=、<、>、<=、>= (§7.10.5(、二进制 + (§7.8.4(、二进制 - (§7.8.5(、^、&、|(§7.11.2(、~ (§7.7.4(、++ 和 -- (§7.6.9 和 §7.7.5(。
基本上,由于枚举在内部存储为Int32
(这是默认值,除非您指定不同的存储类型(,因此您可以使用这样的加法。
但是,使用|
而不是+
来定义掩码更为常见。 此外,如果要将其用作标志枚举,通常包含[Flags]
。
来自枚举上的 C# 参考:
。每个枚举类型都有一个基础类型,该基础类型可以是除 char 之外的任何整型类型。 枚举元素的默认基础类型是 int...
顺便说一下,使用 |
而不是+
来组合枚举标志值更惯用(并且更不容易出错(。例如,此错误不会导致问题:
DenialAcknowledged =
ApprovalItemState.Denied
| ApprovalItemState.Acknowledged
| ApprovalItemState.Denied
但是这个错误会导致一个问题:
DenialAcknowledged =
ApprovalItemState.Denied
+ ApprovalItemState.Acknowledged
+ ApprovalItemState.Denied
Approved + Acknowledged
只是一个常量,因此可以将其作为值分配给枚举元素。关于测试 - 它们有效是因为 int 值是"快乐的",所以(a + b) == (a | b)
但是,如果您将其更改为类似的东西:
public enum ApprovalItemState
{
Enqueued = 1,
Approved = 2,
Denied = 7,
Acknowledged = 18,
ApprovalAcknowledged = Approved + Acknowledged,
DenialAcknowledged = Denied + Acknowledged
}
并且测试不会通过。
并不奇怪 - 枚举由整数类型表示。 您也可以使用其他运算符,但如果要使用标志(此示例正在这样做(,最好使用 [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
}
我将为您分解其中之一。
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
这就是测试通过的原因。通过查看代码并不完全简单。