【问题标题】:Combining Enum Values with Bit-Flags将枚举值与位标志结合起来
【发布时间】:2013-10-25 06:21:37
【问题描述】:

我有这种情况,用户有自己的角色

普通用户
托管人
金融

托管人和财务都是超级用户

我如何检查角色保管人是否是超级用户

这是我的示例代码..

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    public enum Role
    {
        NormalUser = 0,
        Custodian = 1,
        Finance = 2,
        SuperUser = Custodian | Finance,
        All = Custodian | Finance | NormalUser
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Normal: " + Convert.ToInt32(Role.NormalUser));            
            Console.WriteLine("Custodian: " + Convert.ToInt32(Role.Custodian));
            Console.WriteLine("Finance: " + Convert.ToInt32(Role.Finance));            
            Console.WriteLine("SuperUser: " + Convert.ToInt32(Role.SuperUser));
            Console.WriteLine("All: " + Convert.ToInt32(Role.All));

            Console.WriteLine();
            Console.WriteLine("Normal User is in All: {0}", Role.NormalUser == Role.All);
            Console.WriteLine("Normal User is not a SuperUser: {0}", Role.NormalUser != Role.SuperUser);
            Console.WriteLine("Normal User is not a Custodian: {0}", Role.NormalUser != Role.Custodian);

            Console.WriteLine();
            Console.WriteLine("Custodian is in All: {0}", Role.Custodian == Role.All);
            Console.WriteLine("Custodian is a SuperUser: {0}", Role.Custodian == Role.SuperUser);
            Console.WriteLine("Custodian is a NormalUser: {0}", Role.Custodian == Role.NormalUser);

            Console.WriteLine();
            Console.WriteLine("Finance is in All: {0}", Role.Finance == Role.All);
            Console.WriteLine("Finance is a SuperUser: {0}", Role.Finance == Role.SuperUser);
            Console.WriteLine("Finance is a NormalUser: {0}", Role.Finance == Role.NormalUser);

            Console.ReadLine();
        }
    }
}

如果我们运行它,这就是结果

Normal: 0
Custodian: 1
Finance: 2
SuperUser: 3
All: 3

Normal User is in All: False
Normal User is not a SuperUser: True
Normal User is not a Custodian: True

Custodian is in All: False
Custodian is a SuperUser: False
Custodian is a NormalUser: False

Finance is in All: False
Finance is a SuperUser: False
Finance is a NormalUser: False

我期待一个

托管人是所有人:是的
托管人是超级用户:是的
财务是万能的:是的
财务是超级用户:是的
普通用户是全部:是的

【问题讨论】:

标签: c#


【解决方案1】:

Enum.HasFlag 是你要使用的

Console.WriteLine("Custodian is in All: {0}", Role.All.HasFlag(Role.Custodian));

刚刚注意到,您的枚举应该使用 Flags 属性和值以 2 的幂间隔进行定义

[Flags]
public enum Role
{
    NormalUser = 1,
    Custodian = 2,
    Finance = 4,
    SuperUser = Custodian | Finance,
    All = Custodian | Finance | NormalUser
}

2 的幂用于标记枚举的原因是每个 2 的幂都代表在二进制表示中设置的唯一位:

NormalUser = 1 = 00000001
Custodian  = 2 = 00000010
Finance    = 4 = 00000100
Other      = 8 = 00001000

因为枚举中的每个项目都有一个唯一的位设置,这允许通过设置它们各自的位来组合它们。

SuperUser  = 6 = 00000110 = Custodian + Finance
All        = 7 = 00000111 = NormalUser + Custodian + Finance
NormOther  = 9 = 00001001 = NormalUser + Other

注意二进制形式中的每个 1 如何与上面部分中为标志设置的位对齐。

【讨论】:

  • 2 的幂次幂间隔的原因是什么。我知道你应该这样做,但不知道为什么?
  • @DonO 刚刚更新了答案,包括解释为什么使用 2 的幂,在评论中覆盖有点大。希望它有用/有意义。
【解决方案2】:

查看What does the [Flags] Enum Attribute mean in C#? 以获得更详尽的说明。

声明标志的“更安全”的方法是使用位移来确保没有重叠(如@DaveOwen's answer 所述),而无需自己弄清楚数学:

[Flags]
public enum MyEnum
{
    None   = 0,
    First  = 1 << 0,
    Second = 1 << 1,
    Third  = 1 << 2,
    Fourth = 1 << 3
}

还有 Enum.HasFlag(可能比 OP 更新的 .NET)用于检查,而不是 Expected &amp; Testing == Expected

【讨论】:

    【解决方案3】:

    您可以将标志属性添加到枚举中

    [Flags]
    public enum Role
    {
        NormalUser,
        Custodian,
        Finance,
        SuperUser = Custodian | Finance,
        All = Custodian | Finance | NormalUser
    }
    

    然后您可以使用此表达式检查角色:

     Role testRole = Role.Finance
     if(testRole & Role.SuperUser == Role.SuperUser){
          //testRole is SuperUser
     }
    

    【讨论】:

    【解决方案4】:

    我认为这可能与 How do you pass multiple enum values in C#? 重复

    & 位掩码的作用。

    ((Role.NormalUser & Role.All) == Role.NormalUser)
    

    仔细检查你会得到以下信息:

    0b0 & 0b11 == 0b0
    

    但是,如果您说要检查超级用户是否从事财务工作,您将获得以下信息:

    ((Role.SuperUser & Role.Finance) == Role.Finance)
    

    这将评估为:

    0b11 & 0b10 == 0b10
    

    【讨论】:

    • 我不明白为什么。 a &amp; b == c 不是 a == c &amp;&amp; b == c 吗?如果是这样,为什么不a == c?你的Role.All 对我来说在这里看起来不对。不是说你错了。只是说我不明白为什么......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多