문제

아래에 플래그 열거형이 있습니다.

[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.
}

어떻게 하면 이것을 사실로 만들 수 있나요?

도움이 되었습니까?

해결책

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

다른 팁

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

(testItem & FlagTest.Flag1) 비트 AND 연산입니다.

FlagTest.Flag1 는 다음과 같습니다 001 OP의 열거형을 사용합니다.이제 말하자 testItem Flag1과 Flag2가 있습니다(따라서 비트 단위입니다). 101):

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

허용 된 솔루션에서 일어나는 일을 시각화하는 데 어려움이있는 사람들을 위해

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

testItem (질문에 따라) 다음과 같이 정의됩니다.

testItem 
 = flag1 | flag2  
 = 001 | 010  
 = 011

그런 다음 if 문에서 비교의 왼쪽은 다음과 같습니다.

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

그리고 전체 if 문(if가 true로 평가됨) flag1 에 설정되어 있습니다 testItem),

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

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

천만 번 이상의 반복을 수행하는 HasFlags 확장 메서드는 표준 비트 단위 구현의 27ms와 비교하여 무려 4793ms를 사용합니다.

이를 수행하기 위해 확장 방법을 설정했습니다. 관련 질문.

원래:

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

덧붙여서 내가 열거형에 사용하는 규칙은 표준의 경우 단수형, 플래그의 경우 복수형입니다.이렇게 하면 열거형 이름을 통해 여러 값을 보유할 수 있는지 여부를 알 수 있습니다.

조언 하나 더...값이 "0"인 플래그를 사용하여 표준 바이너리 검사를 수행하지 마십시오.이 플래그에 대한 확인은 항상 true입니다.

[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이므로 항상 true입니다.


대신 입력 값이 0인지 간단히 확인해야 합니다.

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

비트 연산의 경우 비트 연산자를 사용해야 합니다.

이렇게 하면 트릭을 수행할 수 있습니다.

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

편집하다: if 검사를 수정했습니다. C/C++ 방식으로 다시 돌아갔습니다(이를 지적한 Ryan Farley에게 감사드립니다).

편집에 관해서.당신은 그것을 사실로 만들 수 없습니다.필요한 구문에 더 가까워지기 위해 원하는 것을 다른 클래스(또는 확장 메서드)로 래핑하는 것이 좋습니다.

즉.

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

이 시도:


if ((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
    // do something
}
기본적으로 코드에서는 두 플래그를 모두 설정하는 것이 하나의 플래그를 설정하는 것과 동일한지 묻고 있으며 이는 분명히 거짓입니다.위의 코드는 Flag1 비트 세트가 설정된 경우에만 그대로 두고 이 결과를 Flag1과 비교합니다.

[Flags]가 없어도 다음과 같은 것을 사용할 수 있습니다

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

또는 0 값 열거형이 있는 경우

if((testItem & (FlagTest.Flag1 | FlagTest.Flag2 ))!=FlagTest.None){
//..
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top