열거형(Enumeration) 타입

열거형(Enumeration) 타입

enum 키워드로 정의하는 열거형 타입은, 정수 계열 숫자 타입의 이름 붙은 상수(named constants) 집합으로 이루어진 값 타입이에요. 여러 선택지 중 하나를 고르거나, 선택지들의 조합을 나타낼 때 사용해요.

출처: Microsoft Learn

본문

열거형을 정의하려면 enum 키워드를 쓰고, 열거 멤버(enum members) 의 이름을 차례대로 나열하면 돼요.

enum Season
{
    Spring,
    Summer,
    Autumn,
    Winter
}

기본적으로 열거 멤버의 연관 상수값은 int 타입이에요. 값은 0에서 시작해서 정의한 순서대로 1씩 늘어나요. 열거형의 기반 타입(underlying type)으로 다른 정수 계열 숫자 타입을 명시할 수도 있고, 연관 상수값을 직접 지정할 수도 있어요. 아래 예시를 볼게요.

enum ErrorCode : ushort
{
    None = 0,
    Unknown = 1,
    ConnectionLost = 100,
    OutlierReading = 200
}

한 가지 짚고 갈 부분이 있는데, 열거형 정의 안에는 메서드를 넣을 수 없어요. 기능을 추가하고 싶다면 확장 멤버(extension member)로 만들어야 해요.

열거형 E의 기본값은 (E)0이라는 식이 만들어내는 값이에요. 그런데 이 값은 0에 해당하는 열거 멤버가 없더라도 그대로 유효하다는 점을 기억해둬야 해요.

0에서의 암시적 변환

C#은 리터럴 0을 어떤 열거형으로든, 그리고 0과 같은 const 값을 열거형으로 암시적으로 변환해줘요. 그런데 열거형에 값이 0인 멤버가 없으면 이 동작 때문에 예상치 못한 결과가 나올 수 있어요.

:::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetZeroConversions":::

위 예시에서 port1port2 둘 다 값 0이 할당되지만, GpioPort에는 그 값에 해당하는 멤버가 없죠. 이때 xref:System.Enum.IsDefined*?displayProperty=nameWithType 메서드를 쓰면 이 값들이 유효하지 않은 열거값임을 확인할 수 있어요.

이런 암시적 변환이 존재하는 이유는, 모든 구조체 타입의 기본 비트 패턴이 0인데 열거형도 그중 하나이기 때문이에요. 다만 이게 코드에 버그를 만들 수도 있어요. 이런 문제를 피하려면 몇 가지를 지켜보세요.

  • 거의 항상 열거형에 값이 0인 멤버를 하나 정의해요.
  • 숫자 타입에서 열거형으로 변환할 때는 xref:System.Enum.IsDefined*?displayProperty=nameWithType로 값을 검증해요.
  • 숫자 매개변수가 암시적으로 열거형으로 변환될 수 있는 상황이라면 조심해서 다뤄요.

열거형 타입은 상호 배타적인 값들의 집합에서 하나를 선택하거나, 선택들의 조합을 나타내는 데 써요. 조합을 나타내려면 열거형을 비트 플래그(bit flags)로 정의해야 해요.

열거형을 비트 플래그로 사용하기

여러 선택지의 조합을 나타내고 싶다면, 각 선택지가 비트 필드가 되도록 열거 멤버를 정의해요. 다시 말해 그 멤버들의 연관값을 2의 거듭제곱으로 사용하는 거예요. 그다음 비트 논리 연산자 |&로 선택지를 합치거나, 조합끼리 교집합을 구하면 돼요. 열거형이 비트 필드를 선언한다는 뜻을 알리려면 Flags 애트리뷰트를 붙여줘요. 아래 예시처럼 일반적인 조합 몇 가지를 정의 안에 함께 넣을 수도 있어요.

:::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetFlags":::

더 자세한 내용과 예시는 xref:System.FlagsAttribute?displayProperty=nameWithTypeNon-exclusive members and the Flags attribute 문서를 참고해요.

System.Enum 타입과 enum 제약 조건

xref:System.Enum?displayProperty=nameWithType 타입은 모든 열거형의 추상 기본 클래스예요. 이 타입은 열거형과 그 값에 대한 정보를 얻기 위한 다양한 메서드를 제공해요. 자세한 내용과 예시는 xref:System.Enum?displayProperty=nameWithType API 참조 페이지에서 확인할 수 있어요.

System.Enum은 기본 클래스 제약 조건(이걸 enum 제약 조건이라고 불러요)에 사용해서, 타입 매개변수가 열거형이라는 걸 지정할 수 있어요. 모든 열거형은 동시에 struct 제약 조건도 만족해요. struct 제약 조건은 타입 매개변수가 non-nullable 값 타입임을 나타낼 때 쓰죠.

변환(Conversions)

모든 열거형에는 열거형과 그 기반 정수 타입 사이의 명시적 변환이 존재해요. 열거값을 기반 타입으로 캐스트하면 결과는 그 멤버의 연관 정수값이 돼요.

:::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetConversions":::

열거형이 특정 연관값을 가진 열거 멤버를 포함하는지 확인하려면 xref:System.Enum.IsDefined*?displayProperty=nameWithType 메서드를 쓰면 돼요.

또한 모든 열거형에는 xref:System.Enum?displayProperty=nameWithType 타입과의 박싱/언박싱(Boxing and unboxing) 변환도 각각 존재해요.

C# 언어 사양

더 자세한 내용은 C# 언어 사양의 다음 섹션을 참고해요.

더 알아보기