열거형(enumeration type)도 값 형식의 하나로 byte, sbyte, short, ushort, int, uint, long, ulong만을 상속받아 정의할 수 있는 제한된 사용자 정의 타입이다.
[접근_제한자] enum 타입명
{
// 숫자를 대표하는 식별자 이름 나열
}
// enum 타입은 숫자형 값에 사람이 인식하기 쉬운 문자열 이름을 부여한다.
// 상속 타입을 지정하지 않는 경우 기본적으로 System.Int32가 된다.
- enum은 내부에 정의된 식별자 순서에 따라 각각 0부터 시작해 1씩 값을 증가시키며 대응시킨다.
- 따라서 예제 코드의 Sunday는 숫자0이고, 그 이후로 1, 2, 3, ...과 같은 식으로 증가해 Saturday는 6이 되어 결국 상속받은 System.Int32 타입에 해당하는 값이 된다.
- enum 변수를 출력했을 때 숫자 0이 아닌 Sunday라는 문자열이 출력된 이유?
- enum의 조상이 System.Object임을 감안하면 enum은 ToString 메서드를 재정의햇고, 그것의 내부 코드에서 숫자값보다는 문자열로 반환하는 역할을 하기 때문이다.
- System.Int32를 부모로 두기 때문에 Days 타입은 int를 비롯해 각종 숫자형 타입과 형 변환하는 것이 가능하고 그 반대도 가능하다.
- 제약이라면 암시적 형 변환이 아닌 명시적 형 변환을 해야한다는 것이다.
enum의 시작 요소 값에 0이 아닌 다른 정수를 지정할 수도 있다.
그 이후의 요소에 대해서도 1씩 자동으로 증가하는 것이 아닌 개발자가 임의의 값을 지정할 수도 있다.
enum Days
{
Sunday = 5, Monday = 10, Tuesday, Wednesday, Thursday = 15, Friday, Saturday
}
위의 경우 각 요소별로 5, 10, 11, 12, 15, 16, 17로 값이 할당된다.
개발자가 값을 할당할 때 주의할 점
- enum이 상속받은 부모의 숫자 타입 범위에 있는 값을 지정해야 한다.
- ex) Days 타입은 int가 부모이므로 long 형에 해당하는 값을 지정하면 컴파일할 때 오류가 발생한다.
- 추가로 enum을 값의 조합으로 사용하는 것도 가능하다.
- ex) Days 인트턴스가 '작업일'이라는 것을 나타내기 위해 Monday 부터 Friday까지의 값을 담을 수 있다.
- 이때 각 요소에 대한 값을 2의 배수로 지정한다.
enum Days
{
Sunday = 1, Moday = 2, Tuesday = 4,
Wednesday = 8, Thursday = 16, Friday = 32, Saturday = 64
}
이렇게 정의하면 다음과 같이 |(OR) 연산자를 사용해 정수형 값을 겹칠 수 있고, HasFlag 메서드를 사용해 특정 요소 값을 포함하고 있는지도 판단할 수 있다.
- 마지막 출력이 62가 나오는데 정수 연산으로 보면 맞는 결과지만, 개별 정수가 의미 있는 식별자로 묶는 것이 enum 타입이라는 점을 감안하면 오히려 출력 값은 'Monday, Tuesday, Wednesday, Thursday, Friday'가 되야 맞다.
- 이런 식으로 enum 타입의 인스턴스가 여러 개의 값을 포함하는 용도로 사용된다는 것을 알리기 위해 [Flags] 특성을 지정할 수 있다.
[Flags] 특성은 enum타입에만 사용될 수 있고 다음과 같이 타입 정의를 할때 함께 지정하면 된다.
- 이렇게 변경하고 다시 실행하면 62가 아닌 문자열이 workingDays의 출력 값으로 나타난다.
- enum을 적절하게 사용하면 코드의 가독성 및 오류를 줄일 수 있다.
- ex) 사칙 연산을 수행하는 메서드를 만든다고 가정하면, enum이 없을 경우 아래와 같은 식으로 메서드를 정의할 것이다.
int Calc(char opType, int operand1, int operand2)
{
switch(opType)
{
case '+' : return operand1 + operand2;
case '-' : return operand1 - operand2;
case '*' : return operand1 * operand2;
case '/' : return operand1 / operand2;
}
return 0;
}
결과적으로 위의 코드는 동작에는 문제가 없지만 향후 유지보수가 번거롭게된다.
- Calc 메서드를 사용하는 측에서 Calc 메서드에서 어떤 연산을 제공하는지 알 수 없으므로 반드시 Calc 내부의 코드를 살펴보거나 제공되는 도움말을 참조해야 한다.
- 또한 개발자가 실수로 오타라도 내면 프로그램이 실행될 때 정상적인 연산이 수행되지 않을 수 있고, 나중에 나머지(%:Remainder)연산을 추가하는 경우 Calc 개발자는 이러한 사실을 반드시 다른 개발자에게 알려야 한다.
이와 같은 다양한 문제를 enum으로 쉽게 해결할 수 있다.
int Calc(CalcType opType, int operand1, int operand2)
{
switch (opType)
{
case CalcType.Add: return operand1 + operand2;
case CalcType.Minus: return operand1 - operand2;
case CalcType.Multiply: return operand1 * operand2;
case CalcType.Divide: return operand1 / operand2;
}
return 0;
}
Calc(CalcType.Add, 5, 6);
- enum을 사용하면 개발자는 CalcType enum 정의만 봐도 지원되는 연산을 짐작할 수 있고, 오타가 발생하더라도 컴파일러가 오류를 발생시킬 것이므로 그에 대한 걱정도 할 필요가 없다.
- 향후 연산이 추가되더라도 CalcType을 참조하는 어떤 개발자라도 쉽게 추가된 사실을 인지할 수 있다.
Reference
시작하세요! C# 12 프로그래밍 기본 문법부터 실전 예제까지
'C#' 카테고리의 다른 글
C# 객체지향 문법 [C#의 클래스 확장 - 멤버 유형 확장] (4) | 2025.07.26 |
---|---|
C# 객체지향 문법 [C#의 클래스 확장 - 구조체] (5) | 2025.06.04 |
C# 객체지향 문법 [C#의 클래스 확장 - 인터페이스] (0) | 2025.05.27 |
C# 객체지향 문법 [C#의 클래스 확장 ~ 델리게이트] (0) | 2025.05.19 |
C# 객체지향 문법 [다형성] (0) | 2025.05.17 |