161

以下にフラグ列挙型があります。

[Flags]
public enum FlagTest
{
    None = 0x0,
    Flag1 = 0x1,
    Flag2 = 0x2,
    Flag3 = 0x4
}

if ステートメントを true に評価することはできません。

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;

if (testItem == FlagTest.Flag1)
{
    // Do something,
    // however This is never true.
}

どうすればこれを実現できますか?

4

11 に答える 11

329

.NET 4 には、新しいメソッドEnum.HasFlagがあります。これにより、次のように記述できます。

if ( testItem.HasFlag( FlagTest.Flag1 ) )
{
    // Do Stuff
}

これははるかに読みやすいです、IMO。

.NET ソースは、これが受け入れられた回答と同じロジックを実行することを示しています。

public Boolean HasFlag(Enum flag) {
    if (!this.GetType().IsEquivalentTo(flag.GetType())) {
        throw new ArgumentException(
            Environment.GetResourceString(
                "Argument_EnumTypeDoesNotMatch", 
                flag.GetType(), 
                this.GetType()));
    }

    ulong uFlag = ToUInt64(flag.GetValue()); 
    ulong uThis = ToUInt64(GetValue());
    // test predicate
    return ((uThis & uFlag) == uFlag); 
}
于 2009-11-20T11:04:36.407 に答える
184
if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
     // Do something
}

(testItem & FlagTest.Flag1)ビット単位のAND演算です。

FlagTest.Flag1001OPの列挙型と同等です。ここで、 testItemFlag1とFlag2があるとしましょう(ビット単位101です):

  001
 &101
 ----
  001 == FlagTest.Flag1
于 2008-09-02T18:31:53.137 に答える
79

受け入れられた解決策 (これはこれです) で何が起こっているのかを視覚化するのに問題がある人のために、

if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // Do stuff.
}

testItem(質問によると)は、次のように定義されます。

testItem 
 = flag1 | flag2  
 = 001 | 010  
 = 011

次に、if ステートメントでは、比較の左側は、

(testItem & flag1) 
 = (011 & 001) 
 = 001

完全な if ステートメント (flag1が に設定されている場合に true と評価されるtestItem)、

(testItem & flag1) == flag1
 = (001) == 001
 = true
于 2009-11-20T11:12:51.123 に答える
26

@phil-devaney

最も単純な場合を除いて、Enum.HasFlagは、コードを手動で書き出す場合と比較してパフォーマンスが大幅に低下することに注意してください。次のコードを検討してください。

[Flags]
public enum TestFlags
{
    One = 1,
    Two = 2,
    Three = 4,
    Four = 8,
    Five = 16,
    Six = 32,
    Seven = 64,
    Eight = 128,
    Nine = 256,
    Ten = 512
}


class Program
{
    static void Main(string[] args)
    {
        TestFlags f = TestFlags.Five; /* or any other enum */
        bool result = false;

        Stopwatch s = Stopwatch.StartNew();
        for (int i = 0; i < 10000000; i++)
        {
            result |= f.HasFlag(TestFlags.Three);
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *4793 ms*

        s.Restart();
        for (int i = 0; i < 10000000; i++)
        {
            result |= (f & TestFlags.Three) != 0;
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *27 ms*        

        Console.ReadLine();
    }
}

1,000 万回以上の反復で、HasFlags 拡張メソッドは、標準のビット単位の実装の 27 ミリ秒と比較して、なんと 4793 ミリ秒かかります。

于 2011-08-23T16:25:40.980 に答える
21

私はそれを行うための拡張メソッドを設定しました:関連する質問

基本的に:

public static bool IsSet( this Enum input, Enum matchTo )
{
    return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}

次に、次のことができます。

FlagTests testItem = FlagTests.Flag1 | FlagTests.Flag2;

if( testItem.IsSet ( FlagTests.Flag1 ) )
    //Flag1 is set

ちなみに、私が列挙型に使用する規則は、標準の場合は単数形、フラグの場合は複数形です。そうすれば、列挙型の名前から、複数の値を保持できるかどうかがわかります。

于 2008-09-02T18:38:17.987 に答える
19

もう1つのアドバイス...値が「0」のフラグを使用して標準のバイナリチェックを実行しないでください。このフラグのチェックは常に真になります。

[Flags]
public enum LevelOfDetail
{
    [EnumMember(Value = "FullInfo")]
    FullInfo=0,
    [EnumMember(Value = "BusinessData")]
    BusinessData=1
}

FullInfoに対して入力パラメータをバイナリチェックすると、次のようになります。

detailLevel = LevelOfDetail.BusinessData;
bool bPRez = (detailLevel & LevelOfDetail.FullInfo) == LevelOfDetail.FullInfo;

bPRezは、ANYTHING&0常に==0として常に真になります。


代わりに、入力の値が0であることを確認するだけです。

bool bPRez = (detailLevel == LevelOfDetail.FullInfo);
于 2010-08-05T07:10:44.263 に答える
7
if((testItem & FlagTest.Flag1) == FlagTest.Flag1) 
{
...
}
于 2008-09-02T18:32:18.673 に答える
5

ビット演算の場合、ビット演算子を使用する必要があります。

これでうまくいくはずです:

if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // Do something,
    // however This is never true.
}

編集: ifチェックを修正しました-C / C ++の方法に戻りました(指摘してくれたRyan Farleyに感謝します)

于 2008-09-02T18:30:25.463 に答える
5

編集について。あなたはそれを真実にすることはできません。必要な構文に近づけるために、必要なものを別のクラス(または拡張メソッド)にラップすることをお勧めします。

すなわち

public class FlagTestCompare
{
    public static bool Compare(this FlagTest myFlag, FlagTest condition)
    {
         return ((myFlag & condition) == condition);
    }
}
于 2008-09-02T18:44:47.520 に答える
4

これを試して:


if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // do something
}
基本的に、コードは両方のフラグを設定することは1つのフラグを設定することと同じであるかどうかを尋ねていますが、これは明らかに誤りです。上記のコードでは、Flag1ビットが設定されている場合はそれだけが設定されたままになり、この結果がFlag1と比較されます。

于 2008-09-02T18:33:12.680 に答える