C# 如何检查是否设置了标志组合的任何标志?

C# 如何检查是否设置了标志组合的任何标志?,c#,enums,flags,C#,Enums,Flags,假设我有这个枚举: [Flags] enum Letters { A = 1, B = 2, C = 4, AB = A | B, All = A | B | C, } 要检查是否设置了例如AB,我可以执行以下操作: if((letter & Letters.AB) == Letters.AB) 有没有比下面更简单的方法来检查是否设置了组合标志常量的任何标志 if((letter & Letters.A) == Letters

假设我有这个枚举:

[Flags]
enum Letters
{
     A = 1,
     B = 2,
     C = 4,
     AB = A | B,
     All = A | B | C,
}
要检查是否设置了例如
AB
,我可以执行以下操作:

if((letter & Letters.AB) == Letters.AB)
有没有比下面更简单的方法来检查是否设置了组合标志常量的任何标志

if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B)
例如,可以用某物交换
&
吗?

怎么样

if((int)letter != 0) { }
if ((letter & Letters.AB) > 0)

如果它真的让你烦恼,你可以编写这样的函数:

public bool IsSet(Letters value, Letters flag)
{
    return (value & flag) == flag;
}

if (IsSet(letter, Letters.A))
{
   // ...
}

// If you want to check if BOTH Letters.A and Letters.B are set:
if (IsSet(letter, Letters.A & Letters.B))
{
   // ...
}

// If you want an OR, I'm afraid you will have to be more verbose:
if (IsSet(letter, Letters.A) || IsSet(letter, Letters.B))
{
   // ...
}

如果您想知道字母在AB中是否有任何字母,必须使用
&
运算符。比如:

if ((letter & Letters.AB) != 0)
{
    // Some flag (A,B or both) is enabled
}
else
{
    // None of them are enabled
}

这对你有用吗

if ((letter & (Letters.A | Letters.B)) != 0)
要检查是否设置了例如AB,我可以执行以下操作:

if((letter & Letters.AB) == Letters.AB)
if((字母和字母.AB)=字母.AB)

有没有比下面更简单的方法来检查是否设置了组合标志常量的任何标志

if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B)
这将检查是否同时设置了A和B,并忽略是否设置了任何其他标志

这将检查是否设置了A或B,并忽略是否设置了任何其他标志

这可以简化为:

if(letter & Letters.AB)
这是用于二进制操作的C;将此应用于C#应该很简单:


顺便提一下,问题示例中变量的命名为单数“字母”,这可能意味着它只代表一个字母;示例代码清楚地表明它是一组可能的字母,并且允许多个值,所以考虑重命名变量“字母”。

< p>您可以检查值是否不是零。< /P>
if ((Int32)(letter & Letters.AB) != 0) { }
<> p>但我认为最好引入一个新的值为0的枚举值,并与此枚举值进行比较(如果可能的话,因为您必须能够修改枚举)。 更新


误读问题-修复了第一个建议,忽略了第二个建议。

我可以看到两个方法,用于检查设置的任何位

A条道路

if (letter != 0)
{
}
只要您不介意检查所有位,包括未定义的位,这就行了

Aproach B

if ((letter & Letters.All) != 0)
{
}
这只检查定义的位,如字母。All表示所有可能的位

对于特定的位(一组或多组),使用A字母B替换字母。所有的位都是要检查的位(见下文)


我使用扩展方法编写如下内容:

if (letter.IsFlagSet(Letter.AB))
    ...
代码如下:

public static class EnumExtensions
{
    private static void CheckIsEnum<T>(bool withFlags)
    {
        if (!typeof(T).IsEnum)
            throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName));
        if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)))
            throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName));
    }

    public static bool IsFlagSet<T>(this T value, T flag) where T : struct
    {
        CheckIsEnum<T>(true);
        long lValue = Convert.ToInt64(value);
        long lFlag = Convert.ToInt64(flag);
        return (lValue & lFlag) != 0;
    }

    public static IEnumerable<T> GetFlags<T>(this T value) where T : struct
    {
        CheckIsEnum<T>(true);
        foreach (T flag in Enum.GetValues(typeof(T)).Cast<T>())
        {
            if (value.IsFlagSet(flag))
                yield return flag;
        }
    }

    public static T SetFlags<T>(this T value, T flags, bool on) where T : struct
    {
        CheckIsEnum<T>(true);
        long lValue = Convert.ToInt64(value);
        long lFlag = Convert.ToInt64(flags);
        if (on)
        {
            lValue |= lFlag;
        }
        else
        {
            lValue &= (~lFlag);
        }
        return (T)Enum.ToObject(typeof(T), lValue);
    }

    public static T SetFlags<T>(this T value, T flags) where T : struct
    {
        return value.SetFlags(flags, true);
    }

    public static T ClearFlags<T>(this T value, T flags) where T : struct
    {
        return value.SetFlags(flags, false);
    }

    public static T CombineFlags<T>(this IEnumerable<T> flags) where T : struct
    {
        CheckIsEnum<T>(true);
        long lValue = 0;
        foreach (T flag in flags)
        {
            long lFlag = Convert.ToInt64(flag);
            lValue |= lFlag;
        }
        return (T)Enum.ToObject(typeof(T), lValue);
    }

    public static string GetDescription<T>(this T value) where T : struct
    {
        CheckIsEnum<T>(false);
        string name = Enum.GetName(typeof(T), value);
        if (name != null)
        {
            FieldInfo field = typeof(T).GetField(name);
            if (field != null)
            {
                DescriptionAttribute attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
                if (attr != null)
                {
                    return attr.Description;
                }
            }
        }
        return null;
    }
}
公共静态类枚举扩展
{
私有静态void CheckIsEnum(bool with flags)
{
if(!typeof(T).IsEnum)
抛出新的ArgumentException(string.Format(“类型“{0}”不是枚举”,类型为(T.FullName));
如果(定义了标志和属性)(类型为(T),类型为(标志属性)))
抛出新的ArgumentException(string.Format(“类型“{0}”没有“Flags”属性,typeof(t.FullName));
}
公共静态bool IsFlagSet(此T值,T标志),其中T:struct
{
CheckIsEnum(真);
长左值=转换为64(值);
long lFlag=Convert.ToInt64(标志);
返回值(左值和lFlag)!=0;
}
公共静态IEnumerable GetFlags(此T值),其中T:struct
{
CheckIsEnum(真);
foreach(Enum.GetValues(typeof(T)).Cast()中的T标志)
{
if(value.IsFlagSet(flag))
收益返回标志;
}
}
公共静态T SetFlags(此T值、T标志、bool on),其中T:struct
{
CheckIsEnum(真);
长左值=转换为64(值);
长lFlag=Convert.ToInt64(标志);
如果(打开)
{
左值|=lFlag;
}
其他的
{
左值&=(~lFlag);
}
返回(T)Enum.ToObject(typeof(T),左值);
}
公共静态T SetFlags(此T值,T标志),其中T:struct
{
返回值.SetFlags(flags,true);
}
公共静态T ClearFlags(此T值,T标志),其中T:struct
{
返回值.SetFlags(flags,false);
}
公共静态T组合标志(此IEnumerable标志),其中T:struct
{
CheckIsEnum(真);
长左值=0;
foreach(标志中的T标志)
{
long lFlag=Convert.ToInt64(标志);
左值|=lFlag;
}
返回(T)Enum.ToObject(typeof(T),左值);
}
公共静态字符串GetDescription(此T值),其中T:struct
{
CheckIsEnum(假);
string name=Enum.GetName(typeof(T),value);
if(name!=null)
{
FieldInfo field=typeof(T).GetField(name);
如果(字段!=null)
{
DescriptionAttribute attr=Attribute.GetCustomAttribute(字段,typeof(DescriptionAttribute))作为DescriptionAttribute;
如果(attr!=null)
{
返回属性描述;
}
}
}
返回null;
}
}
在.NET 4中,您可以使用:

该示例显示以下输出:

//       1 of 3 families in the sample have no pets. 
//       2 of 3 families in the sample have a dog.
在.NET4或更高版本中没有方法

if(letter.HasFlag(Letters.AB))
{
}

如果可以使用.NET 4或更高版本,请使用HasFlag()方法

例子

letter.HasFlag(Letters.A | Letters.B) // both A and B must be set

letter.HasFlag(Letters.AB)

我创建了一个简单的扩展方法,它不需要检查
Enum
类型:

public static bool HasAnyFlag(this Enum value, Enum flags)
{
    return
        value != null && ((Convert.ToInt32(value) & Convert.ToInt32(flags)) != 0);
}
它也适用于可为空的枚举。标准的
HasFlag
方法没有,所以我创建了一个扩展来涵盖这一点

public static bool HasFlag(this Enum value, Enum flags)
{
    int f = Convert.ToInt32(flags);

    return
        value != null && ((Convert.ToInt32(value) & f) == f);
}
一个简单的测试:

[Flags]
enum Option
{
    None = 0x00,
    One = 0x01,
    Two = 0x02,
    Three = One | Two,
    Four = 0x04
}

[TestMethod]
public void HasAnyFlag()
{
    Option o1 = Option.One;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(false, o1.HasFlag(Option.Three));

    o1 |= Option.Two;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(true, o1.HasFlag(Option.Three));
}

[TestMethod]
public void HasAnyFlag_NullableEnum()
{
    Option? o1 = Option.One;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(false, o1.HasFlag(Option.Three));

    o1 |= Option.Two;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(true, o1.HasFlag(Option.Three));
}

享受吧

这里有很多答案,但我认为最惯用的方法是使用字母.AB.hasblag(字母)或(字母.a |字母.B).hasblag(字母),如果你还没有字母.AB。letter.HasFlag(Letters.AB)只有在同时具有这两种功能时才起作用。

对不起,我将在VB中显示它:)

作为整数的公共枚举Cnt
无=0
一=1
二=2
三=4
四=8
结束枚举
子测试()
Dim Cnt值作为新的Cnt
CntValue+=Cnt
public static bool HasAnyFlag(this Enum value, Enum flags)
{
    return
        value != null && ((Convert.ToInt32(value) & Convert.ToInt32(flags)) != 0);
}
public static bool HasFlag(this Enum value, Enum flags)
{
    int f = Convert.ToInt32(flags);

    return
        value != null && ((Convert.ToInt32(value) & f) == f);
}
[Flags]
enum Option
{
    None = 0x00,
    One = 0x01,
    Two = 0x02,
    Three = One | Two,
    Four = 0x04
}

[TestMethod]
public void HasAnyFlag()
{
    Option o1 = Option.One;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(false, o1.HasFlag(Option.Three));

    o1 |= Option.Two;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(true, o1.HasFlag(Option.Three));
}

[TestMethod]
public void HasAnyFlag_NullableEnum()
{
    Option? o1 = Option.One;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(false, o1.HasFlag(Option.Three));

    o1 |= Option.Two;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(true, o1.HasFlag(Option.Three));
}
   <Flags()> Public Enum Cnt As Integer
        None = 0
        One = 1
        Two = 2
        Three = 4
        Four = 8    
    End Enum

    Sub Test()
    Dim CntValue As New Cnt
    CntValue += Cnt.One
    CntValue += Cnt.Three
    Console.WriteLine(CntValue)
    End Sub
public static bool IsSingle(this Enum value)
{
    var items = Enum.GetValues(value.GetType());
    var counter = 0;
    foreach (var item in items)
    {
        if (value.HasFlag((Enum)item))
        {
            counter++;
        }
        if (counter > 1)
        {
            return false;
        }
    }
    return true;
}
if(Letters.AB.HasFlag(Letters.C))