为什么枚举权限通常有0,1,2,4值?

时间:2012-03-21 19:00:43

标签: c# permissions enums flags

为什么人们总是使用0, 1, 2, 4, 8而非0, 1, 2, 3, 4等枚举值?

这与位操作等有关吗?

我真的很感激有关如何正确使用它的小样本片段:)

[Flags]
public enum Permissions
{
    None   = 0,
    Read   = 1,
    Write  = 2,
    Delete = 4
}

7 个答案:

答案 0 :(得分:264)

因为他们是两个人的权力,我可以这样做:

var permissions = Permissions.Read | Permissions.Write;

也许以后......

if( (permissions & Permissions.Write) == Permissions.Write )
{
    // we have write access
}

这是一个位字段,其中每个设置位对应于某些权限(或逻辑上对应的枚举值)。如果这些被定义为1, 2, 3, ...,您将无法以这种方式使用按位运算符并获得有意义的结果。深入研究......

Permissions.Read   == 1 == 00000001
Permissions.Write  == 2 == 00000010
Permissions.Delete == 4 == 00000100

注意这里的模式?现在,如果我们采用我的原始例子,即

var permissions = Permissions.Read | Permissions.Write;

则...

permissions == 00000011

请参阅? ReadWrite位都已设置,我可以独立检查(同时注意Delete设置,因此该值不传达删除权限)。

它允许在一个位字段中存储多个标志。

答案 1 :(得分:144)

如果其他答案仍然不清楚,请考虑这样:

[Flags] 
public enum Permissions 
{   
   None = 0,   
   Read = 1,     
   Write = 2,   
   Delete = 4 
} 

只是一种较短的写作方式:

public enum Permissions 
{   
    DeleteNoWriteNoReadNo = 0,   // None
    DeleteNoWriteNoReadYes = 1,  // Read
    DeleteNoWriteYesReadNo = 2,  // Write
    DeleteNoWriteYesReadYes = 3, // Read + Write
    DeleteYesWriteNoReadNo = 4,   // Delete
    DeleteYesWriteNoReadYes = 5,  // Read + Delete
    DeleteYesWriteYesReadNo = 6,  // Write + Delete
    DeleteYesWriteYesReadYes = 7, // Read + Write + Delete
} 

有八种可能性,但您可以将它们表示为仅有四个成员的组合。如果有十六种可能性,那么您可以将它们表示为仅五个成员的组合。如果有40亿种可能性,那么你可以将它们表示为只有33个成员的组合!显然,只有33个成员,每个(除了零)的权力为2,而不是试图在枚举中命名40亿个项目。

答案 2 :(得分:36)

因为这些值表示二进制中的唯一位位置:

1 == binary 00000001
2 == binary 00000010
4 == binary 00000100

等,所以

1 | 2 == binary 00000011

编辑:

3 == binary 00000011
二进制中的<3>在一个地方和两个地方都由值1表示。它实际上与值1 | 2相同。因此,当您尝试使用二进制位置作为标志来表示某个状态时,3通常不会有意义(除非有逻辑值实际上是两者的组合)

有关进一步说明,您可能希望扩展示例枚举,如下所示:

[Flags]
public Enum Permissions
{
  None = 0,   // Binary 0000000
  Read = 1,   // Binary 0000001
  Write = 2,  // Binary 0000010
  Delete = 4, // Binary 0000100
  All = 7,    // Binary 0000111
}

因此,我有Permissions.All,我也隐含地Permissions.ReadPermissions.WritePermissions.Delete

答案 3 :(得分:9)

[Flags]
public Enum Permissions
{
    None   =    0; //0000000
    Read   =    1; //0000001
    Write  = 1<<1; //0000010
    Delete = 1<<2; //0000100
    Blah1  = 1<<3; //0001000
    Blah2  = 1<<4; //0010000
}

我认为这样的写作更容易理解和阅读,而且你不需要计算它。

答案 4 :(得分:5)

这些用于表示允许枚举值组合的位标志。如果用十六进制表示法编写值,我认为更清楚

[Flags]
public Enum Permissions
{
  None =  0x00,
  Read =  0x01,
  Write = 0x02,
  Delete= 0x04,
  Blah1 = 0x08,
  Blah2 = 0x10
}

答案 5 :(得分:1)

这真的是一个评论,但由于那不支持格式化,我只想包含一个我用来设置标志枚举的方法:

[Flags]
public enum FlagTest
{
    None = 0,
    Read = 1,
    Write = Read * 2,
    Delete = Write * 2,
    ReadWrite = Read|Write
}

在您希望按字母顺序维护标志的情况下,我发现这种方法在开发过程中特别有用。如果您确定需要添加新的标记值,则可以按字母顺序插入,并且您需要更改的唯一值是它现在的值。

但是,请注意,一旦将解决方案发布到任何生产系统(特别是如果枚举是在没有紧密耦合的情况下暴露,例如通过Web服务),那么强烈建议不要更改枚举中的任何现有值

答案 6 :(得分:1)

很多对这个问题的好答案......我只会说..如果你不喜欢,或者不能轻易掌握 <<语法试图表达的内容......我个人更喜欢另一种选择(我敢说,直截了当的枚举声明风格)...

typedef NS_OPTIONS(NSUInteger, Align) {
    AlignLeft         = 00000001,
    AlignRight        = 00000010,
    AlignTop          = 00000100,
    AlignBottom       = 00001000,
    AlignTopLeft      = 00000101,
    AlignTopRight     = 00000110,
    AlignBottomLeft   = 00001001,
    AlignBottomRight  = 00001010
};

NSLog(@"%ld == %ld", AlignLeft | AlignBottom, AlignBottomLeft);

LOG 513 == 513

更容易理解(至少对我自己而言)。排列那些...描述你想要的结果,得到你想要的结果..不需要“计算”。