주녘공부일지

[C#] 열거형 (enum type) 본문

C#/Definition, Etc

[C#] 열거형 (enum type)

주녘 2023. 10. 15. 19:10
728x90

1. 열거형(enum type)이란?

수치 상수에 이름을 붙일 수 있는 특별한 값 형식으로 int 형식의 바탕 값 존재

- 바탕 값은 생략 가능 // 0부터 순서대로 자동 배정 ( 0, 1, 2 ... )

- 일부 멤버들에게만 명시적으로 값을 배정하는 것도 허용하는데, 이 경우 가장 최근 명시적으로 배정된 값을 차례로 증가한 값이 배정되며 같은 바탕 값이 배정될 수 있음

public enum BorderSide
{
    None, // = 0
    Left, // = 1
    Right // = 2
    Top = 5,
    Bottom, // = 6
}

int 형식 이외에도 명시적으로 바탕 정수 값을 배정 가능

- byte, sbyte, short, ushort, int, uint, long, ulong

public enum BorderSide : byte
{
    None, Left, Right, Top, Bottom
}

2. 열거형의 변환

enum 인스턴스를 그 바탕 정수 값 또는 그 반대로 변환할 수 있음 ( 단, 명시적 캐스팅이 필요 )

열거형 사이의 변환에는 바탕 정수 값들이 쓰임

- 수치 리터럴 0은 명시적 캐스팅 없이도 열거형으로 변환 가능

( 열거형의 첫 멤버가 기본 값으로 쓰이는 경우가 많고, 조합된 열거형에서 0은 아무 플래그도 없음을 뜻함 )

public enum HorizontalAlignment
{
    Left = BorderSide.Left, // = 1
    Right = BorderSide.Right, // = 2
    Center // = 3
}

static void Main()
{
    int i = (int)BorderSide.Left; // i = 1
    BorderSide side = (BorderSide)i;

    HorizontalAlignment h = (HorizontalAlignment)(int)BorderSide.Right; // h = 2
    HorizontalAlignment h = (HorizontalAlignment)BorderSide.Right; // int 생략 가능
    
    BorderSide b = 0; // 캐스팅이 필요하지 않음
}

3. 열거형의 조합 (Flags 열거형)

조합된 열거형 값들을 다룰 땐 비트 연산자를 사용 ( 바탕 정수 값에 적용 )

- 일반적으로 비트 연산이 용이하도록 2의 거듭제곱수를 사용

- 편의를 위해, 열거형 선언 자체에서 멤버들을 조합해서 사용 가능

+ 관례적으로 조합 가능 열거형은 Flags 특성을 붙이고, 열거형의 이름을 복수형으로 함

[Flags]
public enum BorderSides
{
    None = 0,
    Left = 1, Right = 2, Top = 4, Bottom = 8,
    LeftRight = Left | Right,
    TopBottom = Top | Bottom,
    All = LeftRight | TopBottom
}

static void Main()
{
    BorderSides leftRight = BorderSides.Left | BorderSides.Right;

    if ((leftRight & BorderSides.Left) != 0) // True
        Console.WriteLine("Left 포함");

    string formatted = leftRight.ToString(); 
    Console.WriteLine(formatted); // Left, Right

    BorderSides s = BorderSides.Left;
    s |= BorderSides.Right;
    Console.WriteLine(s == leftRight); // True
    Console.WriteLine(s); // Left, Right
    
    s ^= BorderSides.Right;
    Console.WriteLine(s); // Left
}

열거형과 정수 형식의 덧셈은 허용되지만, 두 열거형의 덧셈은 불가능하며,

Flags 특성을 붙이지 않은 enum 멤버들도 조합할 수 있지만, 그런 enum의 인스턴스는 이름들의 목록이 아니라 바탕 수치로 비트 연산되어 반환

BorderSides s;
s = BorderSides.Left + 1;
s = BorderSides.Left + (int)BorderSides.Right;
s = BorderSides.Left + BorderSides.Right; // 불가능한 코드

// None = 0, Left = 1, Right = 2, Top = 3

BorderSide side = BorderSide.Left & BorderSide.Right; // None
BorderSide side = BorderSide.Left | BorderSide.Right; // Top

4. 열거형의 형식 안전성 문제

비트연산이나 산술 연산에 의해 열거형 인스턴스의 바탕 값이 유효한 열거형 멤버의 범위를 벗어날 수도 있기 때문에 명시적으로 열거형 값이 유효한지를 체크하는 과정이 필요함

 ex) Enum.IsDefined 메서드로 열거형 유효 값 체크

BorderSide side = (BorderSide)12345;
Console.WriteLine(Enum.IsDefined(typeof(BorderSide), side)); // False

하지만 Enum.IsDefined는 플래그 열거형에 대해서는 제대로 작동하지 않음

- 조합된 플래그 열거형을 유효하게 보지 않음

 ex) 보조 메서드를 선언해 플래그 열거형의 인스턴스의 유효를 판단하는 예시

플러그 열거형에 대해 제대로 작동하지 않는 예시
플래그 열거형의 인스턴스가 유효하면 true를 돌려주는 보조 메서드를 선언한 예시

 

참고도서) C# 6.0 완벽가이드

728x90

'C# > Definition, Etc' 카테고리의 다른 글

[C#] 대리자 (Delegate - Action, Func)  (0) 2023.11.10
[C#] 제네릭 (Generic)  (0) 2023.10.27
[C#] 인터페이스 ( interface )  (0) 2023.10.12
[C#] Object 형식과 박싱&언박싱  (0) 2023.10.11
[C#] 스택 메모리 & 힙 메모리  (0) 2023.10.04