플래그 및 열거형을 사용한 더 스마트한 조건

열거형은 일반적으로 상호 배타적인 값 집합을 정의하는 데 사용됩니다(예: 색상, 요일, 월 등).

그들과 함께 작업할 때 우리는 종종 주어진 값이 열거형의 하위 집합의 일부인지 확인하고 싶습니다. 불행하게도 장황한 조건이 발생하거나 그 중 일부가 상당히 길어서 길이 때문에 버그가 발생하기 쉽습니다.

바라건대, .NET에는 이러한 경우에 보다 스마트하고 깨끗한 조건을 유지하는 데 도움이 되는 매우 깔끔한 기능이 있습니다. 살펴보겠습니다!

사용 사례



사용 사례의 경우 모두 포함하는 DaysOfTheWeek 열거형을 생성해 보겠습니다.

public enum DaysOfTheWeek
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
}


그런 다음 요일에 따라 주어진 서비스의 가격을 계산하려고 합니다.

알고리즘은 그다지 어렵지 않지만 몇 가지 조건이 있습니다.
  • 제공되는 요일이 주말이면 3
  • 제공되는 요일이 월요일, 화요일, 금요일이면 회사
  • 에서 공휴일로 간주하여 1로 표시됩니다.
  • 그렇지 않으면 가격은 2가 됩니다.

  • 이러한 규칙의 첫 번째 구현은 다음과 같습니다.

    public int GetRate(DaysOfTheWeek day)
    {
        if (day == DaysOfTheWeek.Saturday
            || day == DaysOfTheWeek.Sunday)
        {
            return 3;
        }
    
        if (day == DaysOfTheWeek.Monday
            || day == DaysOfTheWeek.Tuesday
            || day == DaysOfTheWeek.Friday)
        {
            return 1;
        }
    
        return 2;
    }
    


    그러나 이러한 알고리즘에는 몇 가지 단점이 있습니다.
  • 세 가지 간단한 조건(많은 OR 및 많은 문자)에 대해 방법이 상당히 "복잡해"보입니다
  • .
  • 우리가 구현한 로직은 그다지 명시적이지 않으며 누군가 코드를 보도록 하면 해당 날짜가 어떻게 선택되는지 묻는 질문이 확실히 생성될 것입니다
  • .

    Flags 속성 소개


    [Flags] 속성을 사용하면 enum 값을 플래그로 사용하여 큰 고통 없이 비트 단위 비교를 수행할 수 있습니다.

    이렇게 하려면 열거형을 다음과 같이 약간만 수정하면 됩니다.
  • [Flags] 속성을 추가
  • 결합할 때 서로 겹치지 않도록 각 열거 상수에 2의 거듭제곱을 할당합니다
  • .

    이렇게 하면 다음 코드가 생성됩니다.

    [Flags]
    public enum DaysOfTheWeek
    {
        Monday    = 1,
        Tuesday   = 2,
        Wednesday = 4,
        Thursday  = 8,
        Friday    = 16,
        Saturday  = 32,
        Sunday    = 64,
    }
    


    열거형을 업데이트하기만 하면 코드가 변경되지 않고 이전 함수가 여전히 훌륭하게 작동합니다. 그러나 이제 HasFlag 메서드를 사용하여 조건에 대한 플래그를 사용하겠습니다.

    public int GetRate(DaysOfTheWeek day)
    {
        if ((DaysOfTheWeek.Saturday | DaysOfTheWeek.Sunday).HasFlag(day))
        {
            return 3;
        }
    
        if ((DaysOfTheWeek.Monday | DaysOfTheWeek.Tuesday | DaysOfTheWeek.Friday).HasFlag(day))
        {
            return 1;
        }
    
        return 2;
    }
    


    이것은 여전히 ​​매우 장황하고 즉시 아무것도 해결하지 못하지만 플래그에 대한 한 가지 흥미로운 점은 열거에서 다른 값의 조합인 값을 정의할 수 있다는 것입니다.

    우리의 경우 주말 전용 값과 특별한 날을 위한 또 다른 값을 가짐으로써 전반적인 가독성을 약간 향상시킬 수 있습니다.

    [Flags]
    public enum DaysOfTheWeek
    {
        Monday    = 1,
        Tuesday   = 2,
        Wednesday = 4,
        Thursday  = 8,
        Friday    = 16,
        Saturday  = 32,
        Sunday    = 64,
    +   Weekend    = Saturday | Sunday,
    +   SpecialDay = Monday | Tuesday | Friday,
    }
    


    이러한 값을 도입함으로써 우리의 코드는 갑자기 훨씬 간단해졌지만 그러한 조건이 있는 이유에 대해 자명하기도 합니다.

    public int GetRate(DaysOfTheWeek day)
    {
        if (DaysOfTheWeek.Weekend.HasFlag(day))
        {
            return 3;
        }
    
        if (DaysOfTheWeek.SpecialDay.HasFlag(day))
        {
            return 1;
        }
    
        return 2;
    }
    


    테이크 아웃



    플래그를 사용하여 여러 열거 상수를 하나의 상수로 결합하여 약간만 변경하여 알고리즘의 의도를 명확히 할 수 있었습니다.

    그러나 플래그가 항상 이러한 문제에 대한 솔루션이 아닐 수 있습니다. 값을 확인하려는 상수의 작은 하위 집합만 있는 경우 복잡성을 감수할 가치가 없을 수 있습니다.

    마찬가지로 데이터베이스에 지속되는 열거형에 플래그를 도입하려면 이전에 저장된 모든 레코드를 업데이트해야 합니다.

    마지막으로, 사용 중인 2의 거듭제곱에 대해 주의해야 합니다. 잘못된 값이나 겹치는 값은 불쾌한 버그를 유발할 수 있습니다.

    As a side note, be very careful when using flags for access rights not to grant anything for the value 0 as 0.HasFlag(/*anything*/) will return true



    추가 팁



    참고로, 2의 거듭제곱을 직접 작성하기에는 너무 장황할 수 있습니다. 왼쪽 시프트 연산자를 사용하여 컴퓨터가 대신 수행하도록 할 수 있습니다!

    [Flags]
    public enum DaysOfTheWeek
    {
        Monday     = 1<<0,  // 1
        Tuesday    = 1<<1,  // 2
        Wednesday  = 1<<2,  // 4
        Thursday   = 1<<3,  // 8
        Friday     = 1<<4,  // 16
        Saturday   = 1<<5,  // 32
        Sunday     = 1<<6,  // 64
        Weekend    = Saturday | Sunday,
        SpecialDay = Monday | Tuesday | Friday,
    }
    


    유용하고 행복한 코딩을 배웠기를 바랍니다.

    좋은 웹페이지 즐겨찾기