Frage

Ich habe unten eine Flag-Aufzählung.

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

Ich kann die if-Anweisung nicht als wahr auswerten lassen.

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;

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

Wie kann ich das wahr machen?

War es hilfreich?

Lösung

In .NET 4 gibt es eine neue Methode Enum.HasFlag.Damit können Sie schreiben:

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

Das ist meiner Meinung nach viel besser lesbar.

Die .NET-Quelle gibt an, dass dies die gleiche Logik wie die akzeptierte Antwort ausführt:

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

Andere Tipps

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

(testItem & FlagTest.Flag1) ist eine bitweise UND-Operation.

FlagTest.Flag1 ist äquivalent zu 001 mit OPs Enumeration.Sagen wir mal testItem hat Flag1 und Flag2 (also bitweise). 101):

  001
 &101
 ----
  001 == FlagTest.Flag1

Für diejenigen, die Schwierigkeiten haben, sich vorzustellen, was mit der akzeptierten Lösung passiert (das ist dieses),

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

testItem (gemäß der Frage) ist definiert als:

testItem 
 = flag1 | flag2  
 = 001 | 010  
 = 011

Dann ist in der if-Anweisung die linke Seite des Vergleichs:

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

Und die vollständige if-Anweisung (die als true if ausgewertet wird flag1 ist eingestellt testItem),

(testItem & flag1) == flag1
 = (001) == 001
 = true

@phil-devaney

Beachten Sie, dass außer in den einfachsten Fällen die Enum.HasFlag Dies führt im Vergleich zum manuellen Ausschreiben des Codes zu erheblichen Leistungseinbußen.Betrachten Sie den folgenden Code:

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

Bei über 10 Millionen Iterationen benötigt die HasFlags-Erweiterungsmethode satte 4793 ms, verglichen mit 27 ms für die bitweise Standardimplementierung.

Ich habe dazu eine Erweiterungsmethode eingerichtet: verwandte Frage.

Grundsätzlich:

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

Dann können Sie Folgendes tun:

FlagTests testItem = FlagTests.Flag1 | FlagTests.Flag2;

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

Im Übrigen verwende ich für Aufzählungen die Konvention Singular für Standard und Plural für Flags.Auf diese Weise wissen Sie anhand des Enum-Namens, ob er mehrere Werte enthalten kann.

Noch ein Ratschlag...Führen Sie niemals die Standard-Binärprüfung mit dem Flag durch, dessen Wert „0“ ist.Ihr Scheck für diese Flagge wird immer wahr sein.

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

Wenn Sie den Eingabeparameter binär mit FullInfo vergleichen, erhalten Sie:

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

bPRez wird immer wahr sein, da ALLES & 0 immer == 0 ist.


Stattdessen sollten Sie einfach überprüfen, ob der Wert der Eingabe 0 ist:

bool bPRez = (detailLevel == LevelOfDetail.FullInfo);
if((testItem & FlagTest.Flag1) == FlagTest.Flag1) 
{
...
}

Für Bitoperationen müssen Sie bitweise Operatoren verwenden.

Das sollte den Zweck erfüllen:

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

Bearbeiten: Meine If-Prüfung wurde korrigiert – ich bin wieder in meine C/C++-Methoden zurückgekehrt (danke an Ryan Farley für den Hinweis)

Bezüglich der Bearbeitung.Du kannst es nicht wahr machen.Ich schlage vor, dass Sie das, was Sie wollen, in eine andere Klasse (oder Erweiterungsmethode) einbinden, um der von Ihnen benötigten Syntax näher zu kommen.

d.h.

public class FlagTestCompare
{
    public static bool Compare(this FlagTest myFlag, FlagTest condition)
    {
         return ((myFlag & condition) == condition);
    }
}

Versuche dies:


if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // do something
}
Im Grunde fragt Ihr Code, ob das Setzen beider Flags dasselbe ist wie das Setzen eines Flags, was offensichtlich falsch ist.Der obige Code lässt nur das Flag1-Bit gesetzt, wenn es überhaupt gesetzt ist, und vergleicht dann dieses Ergebnis mit Flag1.

Auch ohne [Flags] könnten Sie so etwas verwenden

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=0){
//..
}

oder wenn Sie eine Nullwert-Enumeration haben

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top