Quick Reference
enum은 정수 값에 이름을 붙인 타입입니다. 하나만 선택하는 상태는 일반 enum으로, 동시에 켤 수 있는 권한·옵션은 [Flags]와 겹치지 않는 bit 값으로 표현합니다. enum 변수에는 정의되지 않은 숫자도 들어갈 수 있으므로 외부 문자열·정수는 별도로 검증합니다.
public enum JobState : byte
{
Unknown = 0,
Queued = 1,
Running = 2,
Done = 3,
}
[Flags]
public enum Access : byte
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
}- 모든 enum은
(TEnum)0이라는 default value를 가집니다. 0 멤버를 의미 있게 선언합니다. [Flags]의 개별 값은 1, 2, 4처럼 power of two여야 합니다.Enum.TryParse가 성공해도 이름 없는 numeric value일 수 있습니다.
값과 기반 타입
기본 기반 타입은 int이며 byte, sbyte, short, ushort, int, uint, long, ulong 중 하나를 지정할 수 있습니다. 저장소·interop protocol이 요구할 때만 기반 타입과 값을 명시합니다. 단순히 메모리를 줄이려는 이유로 public enum의 기반 타입을 바꾸면 직렬화와 binary compatibility가 깨질 수 있습니다.
public enum HttpResult : short
{
Unknown = 0,
Ok = 200,
NotFound = 404,
}
HttpResult result = (HttpResult)999; // compile/runtime error 없이 가능
bool known = Enum.IsDefined(result); // false0 멤버가 없더라도 default enum field와 default(TEnum)은 0입니다. 이 값이 “아직 지정되지 않음”인지 유효하지 않은 입력인지 구분하려면 Unknown = 0 또는 None = 0을 명시하고 호출자 정책을 정합니다.
Flags 조합과 검사
[Flags]는 enum을 bit field로 사용한다는 의도를 표시합니다. attribute 자체가 bit 연산을 강제하지는 않으므로, 개별 값과 조합 값을 직접 올바르게 정의해야 합니다.
[Flags]
public enum Access : byte
{
None = 0,
Read = 1,
Write = 2,
Delete = 4,
All = Read | Write | Delete,
}
Access access = Access.Read | Access.Write;
bool canWrite = (access & Access.Write) != 0;
access |= Access.Delete;
access &= ~Access.Write;HasFlag도 사용할 수 있지만 access.HasFlag(Access.None)은 항상 true가 될 수 있으므로 “아무 권한도 없음” 검사는 access == Access.None으로 합니다. 허용하지 않는 bit가 섞이지 않았는지 검사할 때는 allowed mask를 만듭니다.
const Access Allowed = Access.Read | Access.Write | Access.Delete;
bool valid = (access & ~Allowed) == 0;Enum.IsDefined는 flags의 이름 있는 단일 값 또는 명시한 조합 이름을 검사할 때는 유용하지만, Read | Write처럼 이름을 따로 정의하지 않은 유효 조합은 false가 될 수 있습니다. flags input은 mask 규칙으로 검증합니다.
문자열·정수 입력
Enum.Parse는 실패하면 예외를 던지고, Enum.TryParse는 이름 또는 numeric text를 변환합니다. user input, HTTP request, config 값은 TryParse 후 해당 enum의 정책을 적용합니다.
static bool TryReadState(string? text, out JobState state)
{
if (Enum.TryParse(text, ignoreCase: true, out state) &&
Enum.IsDefined(state))
{
return true;
}
state = JobState.Unknown;
return false;
}"2"처럼 numeric text는 TryParse에 성공할 수 있으므로, 이름만 허용하는 API라면 입력이 숫자인지 먼저 막거나 허용 문자열 목록을 비교합니다. (JobState)rawValue도 검증을 건너뛰므로 외부 정수에는 Enum.IsDefined 또는 flags mask 검사를 뒤따르게 합니다.
Enum.GetValues<TEnum>()는 UI 선택지나 명시적 mapping을 만들 때 쓸 수 있지만, 외부 API가 새 값을 보낼 수 있는지와 deprecated value를 보일지는 별도의 versioning 정책입니다.
switch와 versioning
enum을 switch로 표시할 때는 알 수 없는 숫자와 미래 서버 값을 처리하는 fallback을 둡니다. 특히 외부 저장소나 네트워크에서 enum 값을 받을 때는 새 버전의 sender가 아직 모르는 값을 보낼 수 있습니다.
string label = state switch
{
JobState.Queued => "queued",
JobState.Running => "running",
JobState.Done => "done",
_ => "unknown",
};값을 저장·전송한다면 이름과 숫자 중 무엇이 contract인지 정하고, 기존 숫자를 재사용하거나 의미를 바꾸지 않습니다. JSON을 문자열 enum으로 바꾸는 converter 설정도 client와 server가 함께 합의해야 합니다.
자주 틀리는 부분
- 0 멤버를 생략하면 default 값이 정의되지 않은 상태가 될 수 있습니다.
[Flags]의 개별 값에 3, 5처럼 겹치는 값을 쓰지 않습니다.Enum.TryParse성공만으로 유효한 업무 값이라고 판단하지 않습니다.- 일반 enum의 순서를 바꿔 숫자가 변해도 안전하다고 가정하지 않습니다.
참고 링크
3 sources