211

私がこの列挙型を持っているとしましょう:

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

たとえば、&何かと交換できますか?

4

18 に答える 18

207

.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.
于 2012-03-20T04:10:19.960 に答える
172

文字に AB の文字が含まれているかどうかを知りたい場合は、AND &演算子を使用する必要があります。何かのようなもの:

if ((letter & Letters.AB) != 0)
{
    // Some flag (A,B or both) is enabled
}
else
{
    // None of them are enabled
}
于 2009-08-27T09:48:58.437 に答える
65

私は拡張メソッドを使用してそのようなものを書きます:

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;
    }
}
于 2009-08-27T10:08:54.387 に答える
42

.NET 4 以降にはHasFlagメソッドがあります。

if(letter.HasFlag(Letters.AB))
{
}
于 2013-06-24T10:54:23.687 に答える
34

HasFlag() メソッドを使用するよりも .NET 4 以降を使用できる場合

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

と同じ

letter.HasFlag(Letters.AB)
于 2014-12-24T13:45:02.490 に答える
14

それが本当に気になるなら、次のような関数を書くことができます:

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))
{
   // ...
}
于 2009-08-27T09:48:24.927 に答える
11

たとえば AB が設定されているかどうかを確認するには、次のようにします。

if((文字 & Letters.AB) == Letters.AB)

結合されたフラグ定数のフラグのいずれかが設定されているかどうかを確認する簡単な方法はありますか?

これは、A と 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));

ちなみに、質問の例の変数の名前は単数形の「文字」です。これは、それが単一の文字のみを表していることを意味する場合があります。サンプルコードは、可能な文字のセットであり、複数の値が許可されていることを明確に示しているため、変数「文字」の名前を変更することを検討してください。

于 2009-08-27T09:53:58.770 に答える
4

どうですか

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

?

于 2009-08-27T09:48:07.813 に答える
3

これはうまくいきますか?

if ((letter & (Letters.A | Letters.B)) != 0)
于 2009-08-27T09:51:20.973 に答える
0

値がゼロでないかどうかを確認できます。

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

しかし、値ゼロの新しい列挙値を導入し、この列挙値と比較する方が良い解決策だと思います (可能であれば、列挙を変更できる必要があるため)。

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

if (letter != Letters.None) { }

アップデート

質問を読み間違えました - 最初の提案を修正し、2 番目の提案を無視してください。

于 2009-08-27T09:56:55.410 に答える
0

設定されているビットをチェックするために機能することがわかる2つのアプローチがあります。

アプローチA

if (letter != 0)
{
}

これは、未定義のものも含め、すべてのビットをチェックすることを気にしない限り機能します!

アプローチ B

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

これは、Letters.All が可能なすべてのビットを表している限り、定義されたビットのみをチェックします。

特定のビット (1 つまたは複数のセット) については、Aproach B を使用して、Letters.All をチェックするビットに置き換えます (以下を参照)。

if ((letter & Letters.AB) != 0)
{
}
于 2009-08-27T10:01:49.783 に答える
0
if((int)letter != 0) { }
于 2009-08-27T09:47:44.570 に答える
-2

申し訳ありませんが、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 したがって、列挙型には 1 + 4 が含まれます

于 2016-07-29T11:36:20.670 に答える