最常见的 C# 枚举按位运算
对于我的一生,我不记得如何在位字段中设置、删除、切换或测试位。 要么我不确定,要么我把它们搞混了,因为我很少需要这些。 因此,如果有一份“小备忘单”就好了。
例如:
flags = flags | FlagsEnum.Bit4; // Set bit 4.
或者
if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?
您能否给出所有其他常见操作的示例,最好是使用 [Flags] 枚举的 C# 语法?
For the life of me, I can't remember how to set, delete, toggle or test a bit in a bitfield. Either I'm unsure or I mix them up because I rarely need these. So a "bit-cheat-sheet" would be nice to have.
For example:
flags = flags | FlagsEnum.Bit4; // Set bit 4.
or
if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?
Can you give examples of all the other common operations, preferably in C# syntax using a [Flags] enum?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
在 .NET 4 中,您现在可以编写:
In .NET 4 you can now write:
习惯用法是使用按位或等于运算符来设置位:
要清除位,习惯用法是使用按位与取反:
有时您有一个偏移量来标识您的位,然后习惯用法是将它们与左移:
The idiom is to use the bitwise or-equal operator to set bits:
To clear a bit, the idiom is to use bitwise and with negation:
Sometimes you have an offset that identifies your bit, and then the idiom is to use these combined with left-shift:
@Drew
请注意,除了最简单的情况外,与手动编写代码相比,Enum.HasFlag 会带来严重的性能损失。 考虑以下代码:
超过 1000 万次迭代,HasFlags 扩展方法花费了高达 4793 毫秒的时间,而标准按位实现只需要 27 毫秒。
@Drew
Note that except in the simplest of cases, the Enum.HasFlag carries a heavy performance penalty in comparison to writing out the code manually. Consider the following code:
Over 10 million iterations, the HasFlags extension method takes a whopping 4793 ms, compared to the 27 ms for the standard bitwise implementation.
不幸的是,.NET 的内置标志枚举操作非常有限。 大多数时候,用户需要弄清楚按位运算逻辑。
在.NET 4中,
HasFlag
方法被添加到Enum
中,这有助于简化用户的代码,但不幸的是它存在很多问题。HasFlag
对于是否检查该值是否具有枚举值参数提供的全部或任何标志这一点不明确。 一切都是顺便说一下。部分由于 .NET 对标志枚举的支持有限,我编写了 OSS 库 枚举。 NET 它解决了所有这些问题并使处理标志枚举变得更加容易。
下面是它提供的一些操作以及仅使用 .NET 框架的等效实现。
组合标志
.NET otherFlags
Enums.NET
flags.CombineFlags(otherFlags)
删除标志
.NET ;
标志 & ~otherFlags
Enums.NET
flags.RemoveFlags(otherFlags)
常见标志
.NET
标志& otherFlags
Enums.NET
flags.CommonFlags(otherFlags)
切换标志
.NET ;
flags ^ otherFlags
Enums.NET
flags.ToggleFlags(otherFlags)
具有所有标志
< b>.NET
(flags & otherFlags) == otherFlags
或 < code>flags.HasFlag(otherFlags)Enums.NET
flags.HasAllFlags(otherFlags)
有任何标志
.NET ;
(flags & otherFlags) != 0
Enums.NET
flags.HasAnyFlags(otherFlags)
获取标志
.NET
Enums.NET
flags.GetFlags()
我正在尝试获取这些改进已纳入 .NET Core 中,并可能最终纳入完整的 .NET Framework 中。 您可以在此处查看我的提案。
.NET's built-in flag enum operations are unfortunately quite limited. Most of the time users are left with figuring out the bitwise operation logic.
In .NET 4, the method
HasFlag
was added toEnum
which helps simplify user's code but unfortunately there are many problems with it.HasFlag
is not type-safe as it accepts any type of enum value argument, not just the given enum type.HasFlag
is ambiguous as to whether it checks if the value has all or any of the flags provided by the enum value argument. It's all by the way.HasFlag
is rather slow as it requires boxing which causes allocations and thus more garbage collections.Due in part to .NET's limited support for flag enums I wrote the OSS library Enums.NET which addresses each of these issues and makes dealing with flag enums much easier.
Below are some of the operations it provides along with their equivalent implementations using just the .NET framework.
Combine Flags
.NET
flags | otherFlags
Enums.NET
flags.CombineFlags(otherFlags)
Remove Flags
.NET
flags & ~otherFlags
Enums.NET
flags.RemoveFlags(otherFlags)
Common Flags
.NET
flags & otherFlags
Enums.NET
flags.CommonFlags(otherFlags)
Toggle Flags
.NET
flags ^ otherFlags
Enums.NET
flags.ToggleFlags(otherFlags)
Has All Flags
.NET
(flags & otherFlags) == otherFlags
orflags.HasFlag(otherFlags)
Enums.NET
flags.HasAllFlags(otherFlags)
Has Any Flags
.NET
(flags & otherFlags) != 0
Enums.NET
flags.HasAnyFlags(otherFlags)
Get Flags
.NET
Enums.NET
flags.GetFlags()
I'm trying to get these improvements incorporated into .NET Core and maybe eventually the full .NET Framework. You can check out my proposal here.
C++ 语法,假设位 0 为 LSB,假设标志为 unsigned long:
检查是否已设置:
检查是否未设置:
设置:
清除:
切换:
C++ syntax, assuming bit 0 is LSB, assuming flags is unsigned long:
Check if Set:
Check if not set:
Set:
Clear:
Toggle:
为了获得最佳性能和零垃圾,请使用:
For the best performance and zero garbage, use this:
按位 (
Flags
) 枚举指南旧的,但想尝试一下备忘单,即使供我自己参考:
|=< /code>
e |= EA
&=
+~
e &= ~EA
^=
e ^= EA
.HasFlag
e.HasFlag(EA)
(e & EA) == EA
示例
奖励:定义一个
Flags
枚举通常,我们使用如下所示的整数:
但是当我们接近更大的数字时,计算下一个值并不那么容易:
但是,有一些替代方案:二进制和十六进制文字。
对于二进制,只需在前一个值的末尾附加一个
0
:十六进制也有一个方便的模式,可能看起来不那么难看:循环 1、2、4、8,每次完成迭代后添加一个零。
Bitwise (
Flags
) enum guideOld, but wanted to take a stab at a cheat sheet, even if for my own reference:
|=
e |= E.A
&=
+~
e &= ~E.A
^=
e ^= E.A
.HasFlag
e.HasFlag(E.A)
(e & E.A) == E.A
Examples
Bonus: defining a
Flags
enumTypically, we use integers like so:
But as we approach larger numbers, it's not as easy to calculate the next value:
There are a couple of alternatives, however: binary and hexadecimal literals.
For Binary, just append a
0
at the end of the previous value:Hexadecimal also has a handy pattern and might look a bit less ugly: cycle through 1, 2, 4, 8, adding a zero after each complete iteration.
要测试一下,您可以执行以下操作:
(假设flags是一个32位数字)
测试位:
(If bit 4 is set then its true)
Toggle Back (1 - 0 or 0 - 1):
Reset Bit 4 to Zero:
To test a bit you would do the following:
(assuming flags is a 32 bit number)
Test Bit:
(If bit 4 is set then its true)
Toggle Back (1 - 0 or 0 - 1):
Reset Bit 4 to Zero:
这是受到 Delphi 中使用 Sets 作为索引器的启发,早在那时:
This was inspired by using Sets as indexers in Delphi, way back when:
C++ 操作有: & | ^ ~(用于与、或、异或和非按位运算)。 同样感兴趣的是>> 和<<,它们是位移操作。
因此,要测试标志中设置的位,您可以使用:
if (flags & 8) //测试位 4 已设置
C++ operations are: & | ^ ~ (for and, or, xor and not bitwise operations). Also of interest are >> and <<, which are bitshift operations.
So, to test for a bit being set in a flag, you would use:
if (flags & 8) //tests bit 4 has been set
我对这些扩展做了更多工作 - 您可以在此处找到代码< /a>
我编写了一些扩展方法来扩展我经常使用的 System.Enum...我并不是说它们是防弹的,但它们有所帮助... 注释已删除...< /em>
然后它们的使用方式如下
I did some more work on these extensions - You can find the code here
I wrote some extension methods that extend System.Enum that I use often... I'm not claiming that they are bulletproof, but they have helped... Comments removed...
Then they are used like the following