아래에 깃발 열거 형이 있습니다.
[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 문 ( flag1
에 설정된 경우 true로 평가됨 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 확장 방법은 1 천만 회 이상 반복되는 표준 비트 구현의 27ms와 비교하여 무려 4793ms가 걸립니다.
답변
확장 방법을 설정했습니다 : related question .
원래:
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”인 플래그로 표준 이진 검사를 수행하지 마십시오. 이 플래그에 대한 귀하의 확인은 항상 사실입니다.
[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);
답변
if((testItem & FlagTest.Flag1) == FlagTest.Flag1)
{
...
}