Jak*_*ade 35 c# bit-manipulation enum-flags
一位开发人员建议我们将一周中的选择日期存储为7个字符的1和0字符串,即周一和周五的"1000100".我更喜欢(强烈建议)一个带有Flags枚举和按位操作的解决方案,我认为这是一种更简洁的方法,对其他开发人员应该更容易理解.
[Flags()]
public enum Weekdays : int
{
Monday = 1,
Tuesday = 2,
Wednesday = 4,
Thursday = 8,
Friday = 16,
Saturday = 32,
Sunday = 64
}
Run Code Online (Sandbox Code Playgroud)
然而,当我开始实现一个示例解决方案时,我意识到简单的字符串方法可能更容易:当然,如果您只是查看数据,则位串比"17"更明显.我发现C#按位运算反直觉且非常冗长:
Weekdays workDays = Weekdays.Monday | Weekdays.Tuesday;
if ((workDays & Weekdays.Monday) == Weekdays.Monday)
{...}
Run Code Online (Sandbox Code Playgroud)
当然,这可以很好地包含在扩展方法中,但是我们突然最终得到的代码行数与字符串解决方案的数量相同,我几乎不能认为按位代码更容易阅读.
话虽这么说,我仍然会使用标志枚举和按位操作.我能想到的主要好处是
那么我如何向同事出售逐位解决方案呢?我是不是该?使用此方法比字符串有什么其他好处?完成示例项目后,我发现团队仍然选择了基于字符串的解决方案.我需要一些更好/更强的论点.为什么要使用Flags枚举而不是简单的位串?
Ran*_*ica 41
使用Flags枚举的好处:
使用Flags枚举的否定:
使用位串的好处:
使用字符串的否定:
能够查看比特串以查看所设置的内容真的有多重要?如果很难知道17是星期一和星期五,你可以随时使用计算器并转换为二进制.或者为"显示"(或调试)使用添加某种字符串表示.这并不是说很难.
在我看来,如果你要使比特串变得坚实,那么你将需要进行相当多的封装,以使其达到Flags枚举已经提供的抽象级别.如果方法是简单地直接操作位串,则难以阅读(并理解)并且可能容易出错.
你最终可能会看到这个:
days = "1000101"; // fixed bug where days were incorrectly set to "1010001"
Run Code Online (Sandbox Code Playgroud)
Ima*_*ist 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以执行以下操作:
Thursday.isWeekday(); // true
Saturday.isWeekday(); // false
Run Code Online (Sandbox Code Playgroud)
创建一个可以保持工作日组合的课程.在类中,您可以以任何方式表示数据,但我肯定会使用标志枚举而不是字符串.在类之外,您只需使用枚举值,并将实际逻辑封装在类中.
就像是:
[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;
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
Weekdays workdays = new Weekdays(Days.MondayToFriday);
if (workdays.Contains(Days.Monday, Days.Wednesday)) {
...
}
Run Code Online (Sandbox Code Playgroud)