본문 바로가기

C#

C# Enum 활용법

Enum은 의미 있는 상수 집합을 타입으로 표현해 코드 가독성과 안전성을 높여줍니다. 기본 사용부터 [Flags] 조합, 파싱, 검증, 성능 포인트까지 실용적으로 정리합니다.

1. 기본 개념과 선언

Enum은 정수 기반의 열거형입니다. 0을 None/Unknown으로 두면 기본값 처리에 유리합니다.

public enum Status
{
    None = 0,
    Pending = 1,
    Active = 2,
    Closed = 3
}

// 사용 예
Status s = Status.Pending;
if (s == Status.Active)
{
    Console.WriteLine("활성 상태입니다.");
}

2. 기본 형식(Underlying Type) 지정

기본 형식은 int이며, 저장 공간이나 비트 마스크 용도에 따라 byte/short/long 등으로 변경할 수 있습니다.

public enum ErrorCode : short
{
    None = 0,
    Minor = 1,
    Major = 2
}

public enum Color8 : byte
{
    None = 0,
    Red = 1,
    Green = 2,
    Blue = 3
}

3. [Flags]로 비트 조합 다루기

비트 플래그는 조합 가능한 옵션을 표현할 때 사용합니다. 2의 거듭제곱으로 정의하고 All을 제공하면 검증이 쉬워집니다.

[Flags]
public enum Permissions : byte
{
    None    = 0,
    Read    = 1 << 0,
    Write   = 1 << 1,
    Execute = 1 << 2,
    All     = Read | Write | Execute
}

var p = Permissions.Read | Permissions.Write;         // 결합
bool canWrite = (p & Permissions.Write) != 0;          // 포함 여부(빠름)
// HasFlag는 간단하지만 상대적으로 느립니다: p.HasFlag(Permissions.Write)

p |= Permissions.Execute;                              // 추가
p &= ~Permissions.Read;                                // 제거
p ^= Permissions.Write;                                // 토글

// 유효성 검사: 정의되지 않은 비트가 있는지 확인
bool valid = (p & ~Permissions.All) == 0;

4. 문자열/숫자 변환과 파싱

사용자 입력이나 설정 값을 Enum으로 안전하게 변환합니다. 플래그는 "Read, Write" 형태도 허용됩니다.

// 문자열 -> Enum (대소문자 무시)
if (Enum.TryParse<Status>("Active", ignoreCase: true, out var status))
{
    Console.WriteLine(status); // Active
}

// 플래그 파싱
Enum.TryParse<Permissions>("Read, Write", out var perms);

// Enum -> 문자열/숫자 포맷
var v = Status.Active;
Console.WriteLine(v.ToString());   // Active
Console.WriteLine(v.ToString("D")); // 2 (십진)
Console.WriteLine(v.ToString("X")); // 00000002 (16진)

var flags = Permissions.Read | Permissions.Write;
Console.WriteLine(flags.ToString("F")); // Read, Write (Flags 서식)

// 숫자 캐스팅
int n = (int)Status.Closed; // 3

5. 안전한 사용과 검증

정수 -> Enum 캐스팅은 항상 성공하지만 값이 정의됐다는 보장은 없습니다. 입력 검증을 습관화합니다.

int raw = 42;
// 위험: 미정의 값이 들어올 수 있음
var s1 = (Status)raw;

// 안전: 정의 여부 확인 (일반적으로 느릴 수 있음)
if (Enum.IsDefined(typeof(Status), raw))
{
    var s2 = (Status)raw;
}

// 범위가 연속적이면 더 빠른 검증도 가능
bool inRange = raw >= (int)Status.None && raw <= (int)Status.Closed;

// Flags 유효성: 정의되지 않은 비트 제거/검증
Permissions fromInput = (Permissions)raw;
bool flagsValid = (fromInput & ~Permissions.All) == 0;

6. switch와 패턴 매칭

switch 식으로 가독성 높은 매핑을 만들 수 있습니다. 기본값은 로깅/폴백 처리로 남겨둡니다.

static string ToTitle(Status s) => s switch
{
    Status.None => "없음",
    Status.Pending => "대기",
    Status.Active => "활성",
    Status.Closed => "종료",
    _ => $"알 수 없음({(int)s})"
};

// Flags에 when 가드 사용
static void Describe(Permissions p)
{
    switch (p)
    {
        case var _ when (p & Permissions.All) == Permissions.All:
            Console.WriteLine("모든 권한");
            break;
        case var _ when (p & Permissions.Write) != 0:
            Console.WriteLine("쓰기 가능");
            break;
        case var _ when p == Permissions.None:
            Console.WriteLine("권한 없음");
            break;
        default:
            Console.WriteLine(p);
            break;
    }
}

7. 반복과 유틸리티

Enum 멤버를 순회하거나, 범용 파서/도우미를 만들어 두면 재사용성이 높아집니다.

// 모든 값 순회 (.NET Core 3.0+)
foreach (Status st in Enum.GetValues<Status>())
{
    Console.WriteLine($"{st} = {(int)st}");
}

// 이름만 필요할 때
foreach (var name in Enum.GetNames<Status>())
{
    Console.WriteLine(name);
}

// 범용 파서: 실패 시 기본값 반환
public static TEnum ParseOrDefault<TEnum>(string? text, TEnum @default)
    where TEnum : struct, Enum
{
    return Enum.TryParse<TEnum>(text, ignoreCase: true, out var value)
        ? value
        : @default;
}

8. 베스트 프랙티스 체크리스트

- 0은 반드시 None/Unknown으로 예약합니다(기본값 안전성).
- 비즈니스 의미가 바뀌지 않도록 값을 명시적으로 할당합니다.
- [Flags]는 2의 거듭제곱과 All 집합을 제공합니다.
- 외부 입력은 TryParse, 범위/비트 마스크로 검증합니다.
- 빈번한 포함 체크는 HasFlag 대신 비트 연산을 사용합니다.
- 새 멤버 추가 시 기본 분기(default)를 통해 하위 호환을 유지합니다.

Enum을 잘 설계하면 매직 넘버를 제거하고, 유지보수와 버그 방지에 큰 도움을 받을 수 있습니다.

'C#' 카테고리의 다른 글

C# 애트리뷰트 (Attribute) 정의와 활용  (0) 2026.04.10
C# StringBuilder로 문자열 성능 최적화  (0) 2026.04.10
C# var와 타입 추론  (0) 2026.04.09
C# 람다 식 (Lambda Expression)  (1) 2026.04.09
C# using 문과 IDisposable  (0) 2026.04.08