一位开发人员建议我们将一周中选择的日期存储为7个字符的1和0字符串,即周一和周五的“1000100”。我更喜欢(强烈建议)一个带有Flags枚举和按位操作的解决方案,我认为这是一种更简洁的方法,对其他开发人员应该更容易理解。
[Flags()]
public enum Weekdays : int
{
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64
}
然而,当我开始实现一个示例解决方案时,我意识到简单的字符串方法可能更容易:当然,如果您只是查看数据,则位串比“17”更明显。而且我发现C#按位运算反直觉而且非常冗长:
Weekdays workDays = Weekdays.Monday | Weekdays.Tuesday;
if ((workDays & Weekdays.Monday) == Weekdays.Monday)
{...}
当然这可以很好地包含在扩展方法中,但是我们突然最终得到的代码行数与字符串解决方案的数量相同,而且我很难说比特代码更容易阅读。
话虽如此,我仍然会使用标志枚举和按位操作。我能想到的主要好处是
那么我如何向同事出售按位解决方案呢?我是不是该?使用此方法比字符串有什么其他好处?完成示例项目后,我发现团队仍然选择了基于字符串的解决方案。我需要一些更好/更强的论点。 为什么要使用Flags枚举而不是简单的位串?
答案 0 :(得分:41)
使用Flags枚举的好处:
使用标志枚举的否定:
使用字符串的好处:
使用字符串的否定:
能够查看比特串以查看所设置的内容真的有多重要?如果很难知道17是星期一和星期五,你可以随时使用计算器并转换为二进制。或者为“显示”(或调试)使用添加某种字符串表示。 并非 。
在我看来,如果你要使比特串变得坚实,那么你将需要进行相当多的封装,以使其达到Flags枚举的抽象级别。提供。如果方法是简单地直接操作位串,则难以阅读(并理解)并且可能容易出错。
e.g。你最终可能会看到这个:
days = "1000101"; // fixed bug where days were incorrectly set to "1010001"
答案 1 :(得分:23)
您不应该创建非标准数据结构来替换标准数据结构(在本例中为DayOfWeek内置枚举)。相反,扩展现有结构。这与您正在讨论的位标记方法的工作方式基本相同。
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;
}
}
}
现在您可以执行以下操作:
Thursday.isWeekday(); // true
Saturday.isWeekday(); // false
答案 2 :(得分:6)
创建一个可以保持工作日组合的课程。在类中,您可以以任何方式表示数据,但我肯定会使用标志枚举而不是字符串。在类之外,您只需使用枚举值,并将实际逻辑封装在类中。
类似的东西:
[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;
}
}
用法示例:
Weekdays workdays = new Weekdays(Days.MondayToFriday);
if (workdays.Contains(Days.Monday, Days.Wednesday)) {
...
}
答案 3 :(得分:1)
问题应该围绕人眼是否真正看到这个储值。如果是这样,一个有点人类可读的格式显然很重要(尽管如果是这样的话,我会为更大的东西做出争论,比如实际名称的数组)。
然而,至少在我构建的所有应用程序中,这种数据在某个地方进入一个小字段并且再也看不到了,除了通过c#代码 - 这意味着bitflags绝对是最简单的 - 它们是代码中最易读的 。你的同事真的想写一个将0和1映射到值的字符串解析器,而不是使用内置和使用40多年按位操作的想法吗?
答案 4 :(得分:0)
有趣的是,这两种方法完全相同;只有flags方法更明显。
我个人会使用这些标志(尽管可能,根据您的模型,最好将列表作为列表存储,不管是谁持有它)。
- 编辑
很明显,我认为,表现真的不需要考虑你正在做的事情。所以只需要最具可读性。 (其中,恕我直言,是命名的旗帜)。
答案 5 :(得分:0)
Flags方法是惯用的(即它是有经验的程序员所做的,习惯于看到和做的,至少在C / C ++ / C#语言中)。