【问题标题】:Bitwise enum cast return value not expected不期望按位枚举转换返回值
【发布时间】:2009-10-21 21:13:57
【问题描述】:

我有以下枚举:

[Flags]
    public enum PermissionLevel {
        User = 1,
        Administrator = 2,
        ITStaff = 3,
        Manager = 4,
        SuperAdministrator = 6,
    }

当我这样做时:

PermissionLevel permission = (PermissionLevel) dr.GetInt32(i);

我得到分配给权限对象的随机权限值。例如,如果 i 为 6,我的权限对象返回“Administrator | Manager”,我应该得到“SuperAdministrator”。当我将实例转换回整数时,它返回 6。

我错过了什么吗?

【问题讨论】:

    标签: c# enums bit-manipulation


    【解决方案1】:

    您需要确保每个值组合都是唯一的:

    [Flags]
    public enum PermissionLevel {
        User = 1,
        Administrator = 2,
        ITStaff = 4,
        Manager = 8,
        SuperAdministrator = 16
    }
    

    正如您当前的枚举所示,6 可以表示SuperAdministratorAdministrator | Manager。 4 可以是ManagerUser | ITStaff 等等。

    【讨论】:

    • 这在文档中指定了吗?
    • 是的,在 Flags 属性的文档中:msdn.microsoft.com/en-us/library/system.flagsattribute.aspx
    • 有一个简单的方法可以避免这个问题:不要使用 1,2,4,8。使用 1
    • @Charles:可能是明智的组合,但肯定不是他所提出的问题。通常,如果您要进行组合,则应使用预定义的 name 而不是数字,以使其明显是组合。 Jason 的建议不是很好也很有效。
    • @Charles:这是你的解释。我只是简单地回答了这个问题,问题正是这些值不是唯一的。我自己经常在枚举中使用组合值,但这不适用于这种情况(我在浏览问题时首先想到的)。
    【解决方案2】:

    没有什么是随机的。如果权限为6,则二进制值为110。有两个活动标志(值为 1 的位),值为 4(管理员)和 2(管理员)的位。您设置的 SuperAdministrator 值 6 实际上是 ManagerAdministrator 的组合。

    有时这是您想要的行为,但似乎不是您的情况。然后,您应该更改您的枚举,以便每个值代表一个唯一的位,正如其他答案所示。

    【讨论】:

    • 谢谢,您的解释对于理解此类枚举的行为非常有用
    【解决方案3】:

    当用 Flags 属性装饰时,你可以做你正在做的事情,这非常好。CLR 告诉你分配给枚举实例的值是管理员或经理......这就是垂直管道is,按位或运算符。
    来自msdn页面msdn Flags Attribute

    "考虑创建一个枚举 常用标志的常量 组合。例如,如果您有 用于文件 I/O 的枚举 包含的操作 枚举常量 Read = 1 和 写 = 2,考虑创建 枚举常量 ReadWrite = Read OR Write,它结合了读取和 写标志。此外,按位 用于组合标志的 OR 操作 可能被认为是先进的 在某些情况下的概念 不应该要求简单 任务。”

    您可以像下面这样轻松地声明枚举:

       [Flags]public enum PermissionLevel 
        {        
           User = 1,        
           Administrator = 2,        
           ITStaff = User | Administrator,        
           Manager = 4,        
           SuperAdministrator = Administrator | Manager ,    
        }
    

    哦,顺便说一句,始终包含 None 值被认为是一种好习惯...

        [Flags]public enum PermissionLevel 
        { 
           None = 0,       
           User = 1,        
           Administrator = 2,        
           ITStaff = User | Administrator,        
           Manager = 4,        
           SuperAdministrator = Administrator | Manager ,    
        }
    

    此技术非常有用,因为它允许客户端代码使用简洁表达实际业务意图的语法针对单个值的子集测试候选值...假设 candValue 是核心单个值之一...

     if ((candValue & PermissionLevel.SuperAdministrator) == candVal) 
         // tests to see if candValue is Administrator Or Manager 
    

    如果您无权访问代表 SuperAdministrator 位掩码 = 00000110 的枚举值,则需要进行 2 次比较

    【讨论】:

      猜你喜欢
      • 2016-11-22
      • 1970-01-01
      • 1970-01-01
      • 2023-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-18
      相关资源
      最近更新 更多