Pregunta

Tengo una enumeración de bandera a continuación.

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

No puedo hacer que la declaración if se evalúe como verdadera.

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;

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

¿Cómo puedo hacer que esto sea cierto?

¿Fue útil?

Solución

En .NET 4 hay un nuevo método Enum.HasFlag.Esto le permite escribir:

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

que es mucho más legible, en mi opinión.

La fuente .NET indica que esto realiza la misma lógica que la respuesta aceptada:

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

Otros consejos

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

(testItem & FlagTest.Flag1) es una operación AND bit a bit.

FlagTest.Flag1 es equivalente a 001 con la enumeración de OP.Ahora digamos testItem tiene Flag1 y Flag2 (por lo que es bit a bit 101):

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

Para aquellos que tienen problemas para visualizar lo que está sucediendo con la solución aceptada (que es esta),

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

testItem (según la pregunta) se define como,

testItem 
 = flag1 | flag2  
 = 001 | 010  
 = 011

Entonces, en la declaración if, el lado izquierdo de la comparación es,

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

Y la declaración if completa (que se evalúa como verdadera si flag1 está preparado testItem),

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

@phil-devaney

Tenga en cuenta que, excepto en los casos más simples, el Enum.HasFlag conlleva una gran penalización de rendimiento en comparación con escribir el código manualmente.Considere el siguiente código:

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

Con más de 10 millones de iteraciones, el método de extensión HasFlags tarda la friolera de 4793 ms, en comparación con los 27 ms de la implementación bit a bit estándar.

Configuré un método de extensión para hacerlo: pregunta relacionada.

Básicamente:

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

Entonces puedes hacer:

FlagTests testItem = FlagTests.Flag1 | FlagTests.Flag2;

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

Por cierto, la convención que uso para las enumeraciones es singular para estándar y plural para banderas.De esa manera, sabrá por el nombre de la enumeración si puede contener múltiples valores.

Un consejo más...Nunca realice la verificación binaria estándar con la bandera cuyo valor es "0".Su verificación de esta bandera siempre será verdadera.

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

Si verifica de forma binaria el parámetro de entrada con FullInfo, obtendrá:

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

bPRez siempre será verdadero como CUALQUIER COSA y 0 siempre == 0.


En su lugar, simplemente deberías comprobar que el valor de la entrada sea 0:

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

Para operaciones de bits, es necesario utilizar operadores bit a bit.

Esto debería funcionar:

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

Editar: Se corrigió mi verificación if: volví a mis costumbres de C/C++ (gracias a Ryan Farley por señalarlo)

Respecto a la edición.No puedes hacerlo realidad.Le sugiero que incluya lo que desea en otra clase (o método de extensión) para acercarse a la sintaxis que necesita.

es decir.

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

Prueba esto:


if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // do something
}
Básicamente, su código pregunta si tener ambas banderas configuradas es lo mismo que tener una bandera configurada, lo cual obviamente es falso.El código anterior dejará solo el bit Flag1 establecido, si es que está configurado, luego comparará este resultado con Flag1.

incluso sin [Banderas], podrías usar algo como esto

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

o si tiene una enumeración de valor cero

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top