열거형
정해진 값 몇 가지에 이름을 붙입니다.
정해진 값 몇 가지에 이름 붙이기
주문 상태를 0·1·2
로 두거나 "대기"·"승인" 같은
문자열로 다루면, 코드 어디에서도 어떤 값이 올 수 있는지 알 수 없습니다.
3 을 담아도, "승인됨" 이라고
오타를 내도 컴파일러는 아무 말이 없습니다.
열거형(enum)은 올 수 있는 값을 미리 늘어놓고 이름을 붙인 형식입니다. 그 목록에 없는 값은 담을 수 없으므로, 잘못이 실행 전에 드러납니다.
- 값마다 이름이 있어 코드를 읽는 것만으로 뜻이 통합니다.
- 목록에 없는 것은 담을 수 없습니다. 오타는 컴파일 오류입니다.
- 밑에는 정수가 깔려 있어 저장하거나 주고받기 좋습니다.
이름 붙은 값 다루기
아래 코드는 브라우저 안에서 실제로 실행됩니다. 고쳐서 눌러 보셔도 됩니다.
var status = Status.Approved; Console.WriteLine(status); Console.WriteLine((int)status); if (status == Status.Approved) { Console.WriteLine("승인되었습니다"); } enum Status { Pending, // 0 — 적지 않으면 0부터 1씩 올라갑니다 Approved, // 1 Rejected // 2 }
코드는 고쳐서 실행해 볼 수 있습니다. 처음 누를 때만 실행기를 내려받느라 잠시 걸립니다. 적은 코드는 서버로 나가지 않습니다.
화면에 찍으면 숫자가 아니라 이름이 나옵니다. 밑에 깔린 정수가
필요하면 (int) 로 꺼내면 됩니다 — 1.4에서 본 캐스트가
여기서도 그대로 쓰입니다.
무엇이 나아지는가
string status = "승인"; // 오타가 그냥 지나갑니다 if (status == "승인됨") { } // 없는 값도 담깁니다 status = "아무거나"; // 무엇이 올 수 있는지 // 코드가 말해 주지 않습니다
Status status = Status.Approved; // 오타는 컴파일 오류 if (status == Status.Approvd) { } // 없는 이름도 컴파일 오류 status = Status.Whatever; // 무엇이 올 수 있는지 // 형식이 알려 줍니다
값을 직접 정하기
적지 않으면 0부터 1씩 올라가지만, 필요하면 직접 정할 수 있습니다. 데이터베이스에 이미 정해진 코드가 있거나, 나중에 항목을 사이에 끼워 넣어도 저장된 숫자가 달라지지 않게 하려면 적어 두는 편이 안전합니다.
enum Level { Guest = 10, Member = 20, Admin = 30 } // 밑바탕 형식도 정할 수 있습니다(기본은 int) enum Small : byte { A, B }
첫 항목은 0이라는 점을 기억해두세요. 열거형의 기본값은 0이므로,
값을 담지 않은 변수나 객체의 필드는 첫 항목이 됩니다. 그래서 첫
자리에 None 이나
Unknown 처럼 "아직 정해지지 않음" 을
두는 것이 널리 쓰이는 관례입니다.
switch 와 함께
열거형은 올 수 있는 값이 정해져 있으므로 1.5의
switch 와 잘 어울립니다. 항목을 빠뜨리면 편집기가
알려 주기도 합니다.
string message = status switch { Status.Pending => "기다리는 중입니다", Status.Approved => "승인되었습니다", Status.Rejected => "반려되었습니다", _ => "알 수 없습니다" };
_ 를 빼지 마세요. 열거형은 정수라서 목록에 없는
값도 담길 수 있습니다 — 밖에서 받은 숫자를 캐스트해 넣으면
(Status)99 같은 것이 들어옵니다. 컴파일러는 막지 않으므로
마지막 자리를 비워 두면 실행 중에 예외가 납니다.
var weird = (Status)99; // 컴파일됩니다 Console.WriteLine(weird); // 99 — 이름이 없어 숫자가 나옵니다 Console.WriteLine(Enum.IsDefined(weird)); // False
여러 개를 함께 담기
권한처럼 여럿을 동시에 가질 수 있는 것은 항목마다 겹치지 않는
비트를 주고 [Flags] 를 붙입니다. 1.4에서 본 비트
연산자가 여기서 제 몫을 합니다.
[Flags] enum Permission { None = 0, Read = 1, // 0001 Write = 2, // 0010 Share = 4 // 0100 } // | 로 합치고 HasFlag 로 물어봅니다 var mine = Permission.Read | Permission.Write; Console.WriteLine(mine); // Read, Write Console.WriteLine(mine.HasFlag(Permission.Write)); // True Console.WriteLine(mine.HasFlag(Permission.Share)); // False
값은 반드시 1, 2, 4, 8… 처럼 자리마다 하나씩 켜지게 주어야 합니다.
3을 주면 이미 Read | Write 와 같아져 섞입니다.
[Flags] 를 붙이면 화면에 찍을 때도 합쳐진 이름을
알아보기 좋게 내줍니다.
이 문법, 몇 버전부터 사용할 수 있나요
- 1.0enum · [Flags] · 밑바탕 형식 지정
- 8.0switch 식으로 항목 분기하기
열거형은 C# 1.0부터 있었고 문법이 거의 바뀌지 않았습니다. 달라진 것은
다루는 방법입니다 — C# 8.0의
switch 식이 항목마다 값을 고르는 코드를 크게
줄였고, 라이브러리 쪽에서도 Enum.TryParse 나
제네릭 Enum.IsDefined 처럼 안전하게 다루는
도구가 더해졌습니다.
직접 해보기
요일을 담는 Day 열거형을 만들고, 받은 요일이 주말인지
평일인지 출력해보세요. 1.5의 switch 식을 사용하면
짧게 적을 수 있습니다.
읽기·쓰기·지우기를 담는 Access 열거형을
[Flags] 로 만들고, 읽기와 쓰기를 함께 가진 값을 만들어
지우기 권한이 있는지 물어보세요.
- 열거형은 올 수 있는 값을 미리 늘어놓고 이름을 붙인 형식입니다.
- 첫 항목은 0이자 기본값입니다. 그 자리에
None을 두는 것이 관례입니다. - 밑에 깔린 것은 정수라 목록에 없는 값도 담길 수 있습니다.
switch식에_를 꼭 두세요. - 여럿을 함께 가지려면
[Flags]와 1·2·4·8… 입니다.
C# 버전별 변경 이력 에서 각 버전이 무엇을 더했는지 볼 수 있습니다.