Programing

플래그 조합의 플래그가 설정되어 있는지 확인하는 방법은 무엇입니까?

알 수 없는 사용자 2020. 5. 30. 09:10
반응형

플래그 조합의 플래그가 설정되어 있는지 확인하는 방법은 무엇입니까?


이 열거 형이 있다고 가정 해 봅시다.

[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)

예를 들어와 &무언가 를 바꿀 수 있습니까?

이진 바이너리에 관해서는 너무 안정적이지 않습니다 ...


AB에 문자가 있는지 확인하려면 AND & 연산자를 사용해야합니다 . 다음과 같은 것 :

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

.NET 4에서는 Enum.HasFlag 메서드를 사용할 수 있습니다 .

using System;

[Flags] public enum Pet {
   None = 0,
   Dog = 1,
   Cat = 2,
   Bird = 4,
   Rabbit = 8,
   Other = 16
}

public class Example
{
   public static void Main()
   {
      // Define three families: one without pets, one with dog + cat and one with a dog only
      Pet[] petsInFamilies = { Pet.None, Pet.Dog | Pet.Cat, Pet.Dog };
      int familiesWithoutPets = 0;
      int familiesWithDog = 0;

      foreach (Pet petsInFamily in petsInFamilies)
      {
         // Count families that have no pets. 
         if (petsInFamily.Equals(Pet.None))
            familiesWithoutPets++;
         // Of families with pets, count families that have a dog. 
         else if (petsInFamily.HasFlag(Pet.Dog))
            familiesWithDog++;
      }
      Console.WriteLine("{0} of {1} families in the sample have no pets.", 
                        familiesWithoutPets, petsInFamilies.Length);   
      Console.WriteLine("{0} of {1} families in the sample have a dog.", 
                        familiesWithDog, petsInFamilies.Length);   
   }
}

예제는 다음 출력을 표시합니다.

//       1 of 3 families in the sample have no pets. 
//       2 of 3 families in the sample have a dog.

나는 확장 메소드를 사용하여 다음과 같은 것을 작성합니다.

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;
    }
}

.NET 4 이상 에는 HasFlag 메소드 가 있습니다 .

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

HasFlag () 메서드를 사용하는 것보다 .NET 4 이상을 사용할 수있는 경우

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

와 동일

letter.HasFlag(Letters.AB)

정말 귀찮다면 다음과 같은 함수를 작성할 수 있습니다.

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 ((문자 및 Letters.AB) == Letters.AB)

결합 플래그 상수의 플래그가 다음보다 설정되어 있는지 확인하는 간단한 방법이 있습니까?

이 있는지 검사 모두 다른 플래그 여부와 B가 설정되고, 무시가 설정된다.

if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B)

이 검사 A 또는 B가 설정되고, 무시는 다른 플래그가 설정되어 있는지의 여부.

다음과 같이 단순화 할 수 있습니다.

if(letter & Letters.AB)

이진 연산을위한 C는 다음과 같습니다. 이것을 C #에 적용하는 것이 간단해야합니다.

enum {
     A = 1,
     B = 2,
     C = 4,
     AB = A | B,
     All = AB | C,
};

int flags = A|C;

bool anything_and_a = flags & A;

bool only_a = (flags == A);

bool a_and_or_c_and_anything_else = flags & (A|C);

bool both_ac_and_anything_else = (flags & (A|C)) == (A|C);

bool only_a_and_c = (flags == (A|C));

Incidentally, the naming of the variable in the question's example is the singular 'letter', which might imply that it represents only a single letter; the example code makes it clear that its a set of possible letters and that multiple values are allowed, so consider renaming the variable 'letters'.


How about

if ((letter & Letters.AB) > 0)

?


I created a simple extension method that does not need a check on Enum types:

public static bool HasAnyFlag(this Enum value, Enum flags)
{
    return
        value != null && ((Convert.ToInt32(value) & Convert.ToInt32(flags)) != 0);
}

It also works on nullable enums. The standard HasFlag method does not, so I created an extension to cover that too.

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

    return
        value != null && ((Convert.ToInt32(value) & f) == f);
}

A simple test:

[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));
}

Enjoy!


Would this work for you?

if ((letter & (Letters.A | Letters.B)) != 0)

Regards,

Sebastiaan


There are a lot of answers on here but I think the most idiomatic way to do this with Flags would be Letters.AB.HasFlag(letter) or (Letters.A | Letters.B).HasFlag(letter) if you didn't already have Letters.AB. letter.HasFlag(Letters.AB) only works if it has both.


if((int)letter != 0) { }

You could just check if the value is not zero.

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

But I would consider it a better solution to introduce a new enumeration value with value zero and compare agains this enumeration value (if possible because you must be able to modify the enumeration).

[Flags]
enum Letters
{
    None = 0,
    A    = 1,
    B    = 2,
    C    = 4,
    AB   =  A | B,
    All  = AB | C
}

if (letter != Letters.None) { }

UPDATE

Missread the question - fixed the first suggestion and just ignore the second suggestion.


There are two aproaches that I can see that would work for checking for any bit being set.

Aproach A

if (letter != 0)
{
}

This works as long as you don't mind checking for all bits, including non-defined ones too!

Aproach B

if ((letter & Letters.All) != 0)
{
}

This only checks the defined bits, as long as Letters.All represents all of the possible bits.

For specific bits (one or more set), use Aproach B replacing Letters.All with the bits that you want to check for (see below).

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

You can use this extension method on enum, for any type of enums:

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;
}

Sorry, but i will show it in VB :)

   <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

CntValue = 5 So the enum contains 1 + 4

참고URL : https://stackoverflow.com/questions/1339976/how-to-check-if-any-flags-of-a-flag-combination-are-set

반응형