代码之家  ›  专栏  ›  技术社区  ›  Jakob Gade

标记枚举和位操作与位字符串

  •  35
  • Jakob Gade  · 技术社区  · 15 年前

    另一位开发人员建议我们将一周中的几天存储为1和0的7字符字符串,即周一和周五的100000。我更喜欢(并且强烈建议)一个带有标志枚举和位操作的解决方案,我认为这是一种更干净的方法,而且对于其他开发人员来说应该更容易理解。

      [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) 
    {...}
    

    当然,这可以很好地包装成扩展方法,但是我们突然得到的代码行数至少与字符串解决方案的代码行数相同,而且我很难说位代码更容易阅读。

    尽管如此,我仍然会使用标志枚举和位操作。我能想到的主要好处是

    • 更好的性能
    • 更少的存储空间

    那么,我该如何向我的同事们推销位解决方案呢?我应该吗?在字符串上使用此方法的其他好处是什么?完成示例项目后,我发现团队仍然选择基于字符串的解决方案。我需要一些更好/更有力的论据。 为什么要使用标志枚举而不是简单的位字符串?

    6 回复  |  直到 12 年前
        1
  •  41
  •   Randy Levy    15 年前

    使用Flags枚举的好处:

    使用标志枚举的负数:

    • 难以理解的人类的数据表示(例如,为17设置了什么标志?)


    使用位串的好处:

    • 便于程序员查看字符串中设置了哪些位

    使用位串的负数:

    • 非标准方法
    • 对于不熟悉您的设计的程序员来说,很难理解
    • 可能更容易设置“垃圾”值(例如,StringValue=“Sunday”)。
    • 不必要的字符串创建
    • 不必要的字符串分析
    • 其他开发工作
    • 重新设计车轮(但不包括圆形车轮)


    能够查看位串以查看设置的内容有多重要?如果很难知道17是星期一和星期五,你可以使用计算器并转换成二进制。或者添加一些字符串表示形式以供“显示”(或调试)使用。不是这样的 那个 很难。


    在我看来,如果要使位串接近实数,那么需要进行相当多的封装,以使其达到标志枚举已经提供的抽象级别。如果方法是直接操作位串,那么这将很难读取(和理解),而且可能容易出错。

    例如,您可能会看到:

    days = "1000101"; // fixed bug where days were incorrectly set to "1010001"
    
        2
  •  23
  •   Imagist    15 年前

    您不应该创建非标准数据结构来替换标准数据结构(在本例中,是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
    
        3
  •  6
  •   Guffa    15 年前

    创建一个可以包含工作日组合的类。在类内部,您可以用任何一种方式表示数据,但我肯定会使用标志枚举,而不是字符串。在类外部,您只使用枚举值,实际逻辑封装在类中。

    类似:

    [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)) {
       ...
    }
    
        4
  •  1
  •   Rex M    15 年前

    问题应该围绕着人类的眼睛是否真的能看到这个存储值。如果是这样的话,那么某种人类可读的格式显然是很重要的(尽管如此,我会为更大的内容(如实名数组)做一个论证)。

    然而,至少在我所构建的所有应用程序中,这种数据都会进入一个很小的领域,再也看不到,除非通过C代码——这意味着位标记绝对是最简单的——它们是人类可读性最高的。 在代码中 . 您的同事确实希望编写一个字符串分析器,将0和1映射到值,而不是使用 内置的 使用40年以上 位运算的概念?

        5
  •  0
  •   Noon Silk    15 年前

    有趣的是,这两种方法完全相同;只有Flags方法更明显。

    我个人会带上旗子(尽管可能,根据您的型号,最好将列表存储为一个列表来对抗持有它的人)。

    --编辑

    我想,要清楚的是,绩效真的不需要考虑你在做什么。所以只要用最可读的。(imho是指名旗)。

        6
  •  0
  •   ChrisW    15 年前

    标志方法是惯用的(也就是经验丰富的程序员所做的和习惯于看到和做的,至少在C/C++/C语言中)。