Pergunta

Eu tenho uma bandeira de enum abaixo.

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

Eu não posso fazer a instrução se é avaliada como verdadeira.

FlagTest testItem = FlagTest.Flag1 | FlagTest.Flag2;

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

Como posso tornar isso verdade?

Foi útil?

Solução

Em .NET 4 há um novo método Enum.HasFlag.Isto permite-lhe escrever:

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

o que é muito mais legível, IMO.

A .Fonte LÍQUIDA indica que executa a mesma lógica que o aceite resposta:

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

Outras dicas

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

(testItem & FlagTest.Flag1) é uma operação AND bit a bit.

FlagTest.Flag1 é equivalente a 001 com o OP é o enum.Agora vamos dizer que testItem tem Sinalizador1 e Flag2 (então ele bit a bit 101):

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

Para aqueles que têm dificuldade de se visualizar o que está acontecendo com o aceite da solução (que é este),

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

testItem (como por pergunta) é definido como,

testItem 
 = flag1 | flag2  
 = 001 | 010  
 = 011

Em seguida, a instrução se, o lado esquerdo da comparação é,

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

E o completo se a instrução (que é avaliada como true se flag1 é definido em testItem),

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

@phil-devaney

Tenha em atenção que excepto, no mais simples dos casos, os Enum.HasFlag carrega uma pesada penalidade de desempenho em comparação ao escrever o código manualmente.Considere o seguinte 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();
    }
}

Mais de 10 milhões de iterações, o HasFlags método de extensão leva uma enorme 4793 ms, em comparação com os 27 ms para o padrão de bit a bit implementação.

Para configurar um método de extensão para fazê-lo: perguntas relacionadas.

Basicamente:

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

Em seguida, você pode fazer:

FlagTests testItem = FlagTests.Flag1 | FlagTests.Flag2;

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

Aliás, a convenção que eu uso para enums é singular por padrão, no plural para bandeiras.De que forma você sabe do enum nome se ele pode armazenar vários valores.

Mais um conselho...Nunca faça o padrão binário de seleção com a bandeira cujo valor é "0".Seu check esta bandeira será sempre verdadeiro.

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

Se você binário de seleção de parâmetro de entrada contra FullInfo - você ganha:

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

bPRez sempre será verdadeiro como QUALQUER coisa & 0 sempre == 0.


Em vez disso, você deve simplesmente verificar que o valor da entrada é de 0:

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

Para operações bit, você precisa usar os operadores bit a bit.

Isso deve fazer o truque:

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

Editar: Fixo os meus se o check - eu escorreguei de volta em minha C/C++ formas (graças a Ryan Farley por apontando para fora)

Sobre o editar.Você não pode torná-la verdadeira.Eu sugiro que você enrole o que você quer em outra classe (ou método de extensão) para aproximar a sintaxe que você precisa.

i.e.

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

Tente isso:


if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // do something
}
Basicamente, o seu código está perguntando se tendo tanto o conjunto de sinalizadores é o mesmo que ter um conjunto de sinalizador, o que é obviamente falso.O código acima vai deixar apenas o Flag1 conjunto de bits se estiver definido, então compara este resultado com Flag1.

mesmo sem [Flags], você pode usar algo como isto

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

ou se você tiver um valor igual a Zero enum

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top