C# 标志枚举和按位运算与“位串”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1285986/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Flags enum & bitwise operations vs. “string of bits”
提问by Jakob Gade
A fellow developer suggested we store a selection of days of the week as 7-character string of 1's and 0's, i.e. “1000100” for Monday and Friday. I preferred (and strongly suggested) a solution with a Flags enum and bitwise operations, I think it's a cleaner way of doing this, and it should be easier to understand for other developers.
一位开发人员建议我们将选择的一周中的几天存储为由 1 和 0 组成的 7 个字符串,即“1000100”代表星期一和星期五。我更喜欢(并强烈建议)使用 Flags 枚举和按位运算的解决方案,我认为这是一种更简洁的方法,并且对于其他开发人员来说应该更容易理解。
[Flags()]
public enum Weekdays : int
{
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64
}
However, as I started to implement a sample solution, I realized that maybe the simple string approach was easier after all: Certainly the bit-string is more obvious than “17” if you're just looking at the data. And I find the C# bitwise operations counter-intuitive and extremely verbose:
然而,当我开始实施一个示例解决方案时,我意识到也许简单的字符串方法毕竟更容易:当然,如果您只是查看数据,位字符串比“17”更明显。我发现 C# 按位运算违反直觉且极其冗长:
Weekdays workDays = Weekdays.Monday | Weekdays.Tuesday;
if ((workDays & Weekdays.Monday) == Weekdays.Monday)
{...}
Of course this could be wrapped nicely into extension methods, but then we suddenly end up with at least the same number of lines of code as with the string-solution, and I can hardly argue the bitwise code is easier to read.
当然,这可以很好地包装到扩展方法中,但是我们突然最终得到的代码行数至少与字符串解决方案相同,而且我很难说按位代码更容易阅读。
That being said, I still would go with a flags enum and bitwise operations. The key benefits I can think of are
话虽如此,我仍然会使用标志枚举和按位运算。我能想到的主要好处是
- Better performance
- Less space needed for storage
- 更好的性能
- 更少的存储空间
So how do I sell the bitwise solution to my colleagues? Should I? What are the other benefits of using this method over strings? After completing the sample project, I found that the team still opted for the string-based solution. I need some better/stronger arguments. Why should you use Flags enums rather than simple bit-strings?
那么我如何向我的同事出售按位解决方案呢?我是不是该?在字符串上使用此方法的其他好处是什么?完成示例项目后,我发现团队仍然选择了基于字符串的解决方案。我需要一些更好/更有力的论据。为什么要使用 Flags 枚举而不是简单的位串?
采纳答案by Randy supports Monica
Benefits of using Flags enum:
使用 Flags 枚举的好处:
- Standard approach: "They are the correct design to use when multiple enumeration values can be specified at the same time."
- Intent is clear
- Maintainable -- new programmers should pick this up easily
- Easily extensible -- support for new flag combinations (e.g. weekend)
- Fast
- 标准方法:“当可以同时指定多个枚举值时,它们是正确的设计。”
- 意图很明确
- 可维护——新程序员应该很容易掌握
- 易于扩展——支持新的标志组合(例如周末)
- 快速地
Negatives of using Flags enum:
使用 Flags 枚举的负面影响:
- Data representation for humans hard to understand (e.g. what flags are set for 17?)
- 人类难以理解的数据表示(例如,为 17 设置了哪些标志?)
Benefits of using string of bits:
使用位串的好处:
- Easy for programmers to see which bits are set in string
- 程序员很容易看到字符串中设置了哪些位
Negatives of using string of bits:
使用位串的否定:
- Non-standard approach
- Harder to understand for programmers unfamiliar with your design
- Potentially easier to set "garbage" values (e.g. stringValue = "Sunday")
- Needless string creation
- Needless string parsing
- Additional development work
- Reinventing the wheel (but not even a round wheel)
- 非标准方法
- 对于不熟悉你的设计的程序员来说更难理解
- 可能更容易设置“垃圾”值(例如 stringValue =“Sunday”)
- 不必要的字符串创建
- 不必要的字符串解析
- 额外的开发工作
- 重新发明轮子(但甚至不是圆轮)
How important is it really to be able to look at the string of bits to see what is set? If it's hard to know that 17 is Monday and Friday, you can always use calculator and convert to binary. Or add some sort of string representation for "display" (or debugging) use. It's not thatdifficult.
能够查看位串以了解设置的内容到底有多重要?如果很难知道 17 是星期一和星期五,您可以随时使用计算器并转换为二进制。或者为“显示”(或调试)使用添加某种字符串表示。这并不是说很难。
It also seems to me that if you are going to make the string of bits approach solid then you will need to do quite a bit of encapsulation to bring it up to a level of abstraction that the Flags enum already provides. If the approach is to simply manipulate the string of bits directly then that is going to be hard to read (and understand) and probably error prone.
在我看来,如果您要使位串接近可靠,那么您将需要进行大量封装以使其达到 Flags 枚举已经提供的抽象级别。如果该方法是简单地直接操作位串,那么这将难以阅读(和理解)并且可能容易出错。
e.g. you may end up seeing this:
例如,您最终可能会看到:
days = "1000101"; // fixed bug where days were incorrectly set to "1010001"
回答by Noon Silk
Amusingly both of those methods are exactly the same; only the flags method is more obvious.
有趣的是,这两种方法完全一样。只有 flags 方法更明显。
I'd personally go with the flags (though potentially, depending on your model, it'd be better just to store the list as an List against whoever is holding it).
我个人会使用这些标志(尽管可能,取决于您的模型,最好将列表存储为针对持有它的人的列表)。
-- Edit
- 编辑
And to be clear, performance really doesn't need to be a consideration for what you're doing, I think. So just go with the most readable. (Which, IMHO, is the named flags).
需要明确的是,我认为实际上不需要考虑你正在做的事情。所以只用最易读的。(恕我直言,这是命名标志)。
回答by Rex M
The question should center around whether human eyes will ever actually see this stored value. If so, a somewhat human-readable format is obviously important (though if that is the case, I'd make an argument for something even larger, like an array of the real day names).
问题应该围绕人眼是否真的会看到这个存储的值。如果是这样,某种人类可读的格式显然很重要(尽管如果是这种情况,我会为更大的内容提出论据,例如真实日期名称的数组)。
However, at least in all the apps I've ever built, this kind of data goes into a tiny field somewhere and is never seen again, except via the c# code - which means bitflags are definitely the simplest - they are the most human-readable in code. Your colleagues really want to write a string parser that maps 0's and 1's to values instead of using the built inand used for 40+ yearsidea of bitwise operations?
然而,至少在我构建的所有应用程序中,这种数据进入某个地方的一个小字段并且再也不会被看到,除非通过 c# 代码——这意味着 bitflags 绝对是最简单的——它们是最人性化的——代码可读。您的同事真的想编写一个字符串解析器,将 0 和 1 映射到值,而不是使用内置并用于 40 多年按位运算的想法?
回答by ChrisW
The Flags method is idiomatic (i.e. it's what experienced programmers do and are accustomed to seeing and doing, at least in C/C++/C# languages).
Flags 方法是惯用的(即它是有经验的程序员所做的并且习惯于看到和做的事情,至少在 C/C++/C# 语言中)。
回答by Guffa
Make a class that can hold the combination of weekdays. Inside the class you can represent the data either way, but I would definitely go for a flags enumeration rather than a string. Outside the class you just use the enum values, and the actual logic is encapsulated in the class.
做一个可以容纳平日组合的班级。在类中,您可以用任何一种方式表示数据,但我肯定会使用标志枚举而不是字符串。在类之外,您只需使用枚举值,而实际的逻辑则封装在类中。
Something like:
就像是:
[Flags]
public enum Days {
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64,
MondayToFriday = 31,
All = 127,
None = 0
}
public class Weekdays {
private Days _days;
public Weekdays(params Days[] daysInput) {
_days = Days.None;
foreach (Days d in daysInput) {
_days |= d;
}
}
public bool Contains(Days daysMask) {
return (_days & daysMask) == daysMask;
}
public bool Contains(params Days[] daysMasks) {
Days mask = Days.None;
foreach (Days d in daysMasks) {
mask |= d;
}
return (_days & mask) == mask;
}
}
Usage example:
用法示例:
Weekdays workdays = new Weekdays(Days.MondayToFriday);
if (workdays.Contains(Days.Monday, Days.Wednesday)) {
...
}
回答by Imagist
You shouldn't be creating non-standard datastructures to replace a standard data structure (in this case, the DayOfWeek builtin enum). Instead, extend the existing structure. This works essentially the same way as the bit flags method you were talking about.
您不应该创建非标准数据结构来替换标准数据结构(在本例中为 DayOfWeek 内置枚举)。相反,扩展现有结构。这与您正在谈论的 bit flags 方法的工作方式基本相同。
namespace ExtensionMethods
{
public static class Extensions
{
/*
* Since this is marked const, the actual calculation part will happen at
* compile time rather than at runtime. This gives you some code clarity
* without a performance penalty.
*/
private const uint weekdayBitMask =
1 << Monday
| 1 << Tuesday
| 1 << Wednesday
| 1 << Thursday
| 1 << Friday;
public static bool isWeekday(this DayOfWeek dayOfWeek)
{
return 1 << dayOfWeek & weekdayBitMask > 0;
}
}
}
Now you can do the following:
现在您可以执行以下操作:
Thursday.isWeekday(); // true
Saturday.isWeekday(); // false