C#에서 열거형(Enum)은 관련된 명명된 상수 집합을 정의하는 데 사용되는 특별한 값 형식입니다. 프로그래머가 코드의 가독성을 높이고, 잠재적인 오류를 줄이며, 유지보수성을 향상시키는 데 큰 도움을 줍니다. 마치 여러 개의 상수를 하나의 카테고리 아래 묶어놓은 사전과 같다고 이해할 수 있습니다. 예를 들어, 요일을 나타내는 숫자 0부터 6까지를 각각 월요일, 화요일 등으로 이름 붙여 사용하는 것과 같습니다.
열거형(Enum)의 기본 개념
열거형은 enum 키워드를 사용하여 선언합니다. 기본적으로 열거형의 각 멤버는 정수 값을 가집니다. 명시적으로 값을 할당하지 않으면 첫 번째 멤버는 0, 그 다음 멤버는 1, 이런 식으로 자동으로 1씩 증가하는 정수 값이 할당됩니다.
C#
// 기본 열거형 선언 예시
public enum DayOfWeek
{
Sunday, // 0
Monday, // 1
Tuesday, // 2
Wednesday, // 3
Thursday, // 4
Friday, // 5
Saturday // 6
}
위 예시에서 DayOfWeek는 열거형의 이름이고, Sunday, Monday 등은 열거형의 멤버(혹은 열거자)입니다. 각 멤버는 내부적으로 정수 값을 가지고 있습니다.
명시적 값 할당
열거형 멤버에 명시적으로 값을 할당할 수 있습니다. 이 경우, 값을 할당하지 않은 다음 멤버는 바로 이전 멤버의 값에서 1 증가된 값을 가집니다.
C#
public enum Season
{
Spring = 1,
Summer, // 2
Autumn = 5,
Winter // 6
}
이 예시에서 Spring은 1, Summer는 2, Autumn은 5, Winter는 6의 값을 가집니다.
열거형의 데이터 형식
열거형의 기본 정수 형식은 **int**입니다. 그러나 byte, sbyte, short, ushort, int, uint, long, ulong과 같은 다른 정수 형식을 명시적으로 지정할 수 있습니다. 이는 특히 메모리 효율성을 고려하거나, 특정 시스템과의 상호 운용성을 위해 유용할 수 있습니다.
C#
public enum ErrorCode : short
{
Success = 0,
InvalidInput = 101,
DatabaseError = 200,
NetworkError = 300
}
위 ErrorCode 열거형은 short 형식으로 정의되었으므로, 각 멤버는 short 범위 내의 값을 가집니다.
열거형(Enum)의 사용 목적 및 장점
열거형을 사용하는 주된 목적은 코드의 명확성, 안전성, 유지보수성을 높이는 것입니다.
코드 가독성 향상: "마법의 숫자(Magic Number)" 사용을 피할 수 있습니다. 예를 들어, 숫자 0, 1, 2 대신 DayOfWeek.Sunday, DayOfWeek.Monday와 같이 의미 있는 이름을 사용하여 코드를 훨씬 더 읽기 쉽게 만듭니다. 이는 코드를 처음 접하는 사람이나 오랜 시간이 지난 후 다시 코드를 봐야 하는 개발자에게 큰 도움이 됩니다.
C#
// 열거형 사용 전
int day = 0; // 0이 무슨 의미인지 알기 어렵다.
if (day == 0) { /* ... */ }
// 열거형 사용 후
DayOfWeek today = DayOfWeek.Sunday; // 명확하게 일요일임을 알 수 있다.
if (today == DayOfWeek.Sunday) { /* ... */ }
오류 감소 및 타입 안전성: 특정 값으로 제한된 선택지를 제공함으로써 유효하지 않은 값이 할당되는 것을 방지합니다. 예를 들어, 요일은 일곱 가지뿐인데, 정수형 변수에 100과 같은 무의미한 값을 할당하는 것을 막을 수 있습니다. 컴파일러는 열거형이 아닌 다른 형식의 값을 열거형 변수에 직접 할당하는 것을 허용하지 않아 타입 안전성을 보장합니다.
C#
DayOfWeek currentDay;
// currentDay = 10; // 컴파일 오류 발생 (int를 DayOfWeek로 암시적 변환할 수 없습니다.)
currentDay = DayOfWeek.Friday; // 올바른 할당
코드 유지보수성 향상: 상수의 값을 변경해야 할 때, 열거형을 사용하면 열거형 정의만 수정하면 됩니다. 만약 상수를 직접 코드 곳곳에 사용했다면, 해당 상수가 사용된 모든 곳을 찾아 일일이 수정해야 하는 번거로움과 오류의 위험이 있습니다.
자동 완성 기능 지원: Visual Studio와 같은 IDE에서 열거형 멤버는 자동 완성(IntelliSense) 기능의 도움을 받을 수 있어 개발 생산성을 높입니다.
열거형(Enum)의 활용
열거형은 다양한 시나리오에서 유용하게 사용될 수 있습니다.
1. 상태 값 정의
게임의 캐릭터 상태, 주문 처리 단계, 네트워크 연결 상태 등 특정 개체의 가능한 상태를 정의할 때 열거형은 매우 효과적입니다.
C#
public enum PlayerState
{
Idle,
Walking,
Running,
Jumping,
Attacking,
Dead
}
PlayerState currentPlayerState = PlayerState.Idle;
if (currentPlayerState == PlayerState.Dead)
{
Console.WriteLine("Game Over!");
}
2. 옵션 및 플래그 정의 (Flags Enum)
하나의 변수에 여러 개의 열거형 멤버를 동시에 할당해야 할 때, 비트 플래그(bit flags)로 사용되는 Flags 특성을 가진 열거형을 활용할 수 있습니다. 이 경우, 각 열거형 멤버는 2의 거듭제곱 값(1, 2, 4, 8, ...)을 가져야 합니다.
C#
[Flags] // Flags 특성
public enum Permissions
{
None = 0,
Read = 1, // 0001
Write = 2, // 0010
Execute = 4, // 0100
Delete = 8, // 1000
All = Read | Write | Execute | Delete // 1111 (1+2+4+8=15)
}
Permissions userPermissions = Permissions.Read | Permissions.Write;
// 특정 권한이 있는지 확인
if (userPermissions.HasFlag(Permissions.Write))
{
Console.WriteLine("쓰기 권한이 있습니다.");
}
// 모든 권한 확인
if ((userPermissions & Permissions.Read) == Permissions.Read)
{
Console.WriteLine("읽기 권한이 있습니다.");
}
[Flags] 특성은 .NET Framework가 열거형 값을 문자열로 변환할 때, 각 플래그를 구분하여 보여주도록 지시하는 역할을 합니다. HasFlag 메서드는 특정 플래그가 설정되었는지 확인하는 데 사용됩니다. 비트 OR(|) 연산자로 여러 플래그를 조합하고, 비트 AND(&) 연산자로 플래그를 확인할 수 있습니다.
3. 메서드 매개변수 및 반환 형식
메서드에 전달되는 매개변수의 유효한 값을 제한하거나, 메서드의 반환 값으로 특정 상태나 결과를 나타낼 때 열거형을 사용합니다.
C#
public enum OperationResult
{
Success,
Failed,
Unauthorized,
NotFound
}
public OperationResult ProcessData(string data)
{
if (string.IsNullOrEmpty(data))
{
return OperationResult.Failed;
}
// 데이터 처리 로직...
return OperationResult.Success;
}
OperationResult result = ProcessData("some data");
if (result == OperationResult.Success)
{
Console.WriteLine("데이터 처리 성공!");
}
열거형(Enum)과 관련된 유용한 메서드
C#의 Enum 클래스는 열거형과 상호 작용하는 데 유용한 정적 메서드를 제공합니다.
1. Enum.GetName(Type enumType, object value)
주어진 열거형 형식과 값에 해당하는 멤버의 이름을 문자열로 반환합니다.
C#
string dayName = Enum.GetName(typeof(DayOfWeek), 3); // "Wednesday"
Console.WriteLine(dayName);
2. Enum.GetNames(Type enumType)
주어진 열거형 형식의 모든 멤버 이름을 포함하는 문자열 배열을 반환합니다.
C#
string[] dayNames = Enum.GetNames(typeof(DayOfWeek));
foreach (string name in dayNames)
{
Console.WriteLine(name);
}
// 출력:
// Sunday
// Monday
// ...
3. Enum.GetValues(Type enumType)
주어진 열거형 형식의 모든 멤버 값을 포함하는 배열을 반환합니다. 반환 형식은 Array이므로 적절한 캐스팅이 필요할 수 있습니다.
C#
Array dayValues = Enum.GetValues(typeof(DayOfWeek));
foreach (DayOfWeek day in dayValues)
{
Console.WriteLine($"Name: {day}, Value: {(int)day}");
}
// 출력:
// Name: Sunday, Value: 0
// Name: Monday, Value: 1
// ...
4. Enum.Parse(Type enumType, string value, bool ignoreCase)
문자열 이름을 열거형 멤버로 변환합니다. ignoreCase 매개변수가 true이면 대소문자를 구분하지 않습니다.
C#
DayOfWeek parsedDay = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), "Friday");
Console.WriteLine(parsedDay); // Friday
DayOfWeek anotherDay = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), "sunday", true);
Console.WriteLine(anotherDay); // Sunday
try
{
DayOfWeek invalidDay = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), "Funday");
}
catch (ArgumentException ex)
{
Console.WriteLine($"오류: {ex.Message}"); // 요청한 열거형에 정의되지 않은 값입니다.
}
5. Enum.TryParse<TEnum>(string value, out TEnum result) 또는 Enum.TryParse<TEnum>(string value, bool ignoreCase, out TEnum result)
Enum.Parse와 유사하지만, 변환에 실패하더라도 예외를 발생시키지 않고 false를 반환합니다. 이는 안전한 변환을 위해 선호됩니다.
C#
DayOfWeek parsedDayResult;
bool success = Enum.TryParse("Saturday", out parsedDayResult);
if (success)
{
Console.WriteLine($"변환 성공: {parsedDayResult}"); // 변환 성공: Saturday
}
bool fail = Enum.TryParse("InvalidDay", out parsedDayResult);
if (!fail)
{
Console.WriteLine("변환 실패!"); // 변환 실패!
}
열거형(Enum) 사용 시 주의사항
값 범위: 열거형의 기본 형식은 int이므로, 멤버의 값이 int의 범위를 초과하지 않도록 주의해야 합니다. 더 큰 값이 필요하면 long과 같은 다른 정수 형식을 명시적으로 지정해야 합니다.
0 값: 특별한 의미를 가지는 0 값은 보통 None, Unknown, Default와 같은 의미로 사용되는 경우가 많습니다. Flags 열거형에서는 None = 0으로 두어 어떤 플래그도 설정되지 않음을 나타냅니다.
직렬화: 열거형을 직렬화할 때, 값을 정수 대신 이름으로 직렬화하는 것이 버전 관리 측면에서 더 안전할 수 있습니다. (예: JSON 직렬화 시 문자열로)
확장성: 열거형은 컴파일 시점에 결정되는 고정된 집합입니다. 런타임에 동적으로 변경되거나 확장되어야 하는 경우에는 열거형보다 클래스나 인터페이스를 사용하는 것이 더 적합할 수 있습니다.
유니티 엔진과 열거형
유니티 엔진에서 열거형은 스크립트 작성 시 매우 광범위하게 사용됩니다. 특히 인스펙터 창에서 값을 시각적으로 선택할 수 있도록 하여 디자이너나 다른 개발자들이 스크립트 설정을 쉽게 변경할 수 있게 합니다.
유니티 인스펙터에서의 열거형
C# 스크립트에서 public으로 선언된 열거형 변수는 유니티 에디터의 인스펙터 창에 드롭다운 메뉴로 나타납니다.
C#
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public enum PlayerMovementState
{
Idle,
Walking,
Running,
Jumping
}
public PlayerMovementState currentState;
void Start()
{
currentState = PlayerMovementState.Idle;
}
void Update()
{
if (currentState == PlayerMovementState.Walking)
{
// 걷는 로직
}
else if (currentState == PlayerMovementState.Jumping)
{
// 점프 로직
}
}
}
위 스크립트를 유니티 오브젝트에 추가하면 인스펙터에서 Current State라는 드롭다운 메뉴를 통해 Idle, Walking, Running, Jumping 중 하나를 선택할 수 있습니다. 이는 복잡한 로직 없이도 게임 오브젝트의 상태를 쉽게 제어하고 테스트할 수 있게 해줍니다.
[Flags] 열거형과 유니티
[Flags] 특성을 사용한 열거형도 유니티 인스펙터에서 특별한 방식으로 표시됩니다. 여러 개의 옵션을 동시에 선택할 수 있는 체크박스 그룹으로 나타나므로, 게임 오브젝트에 여러 개의 속성이나 권한을 부여할 때 유용합니다.
C#
using UnityEngine;
using System; // Flags 특성을 사용하기 위해 필요
public class ItemProperties : MonoBehaviour
{
[Flags]
public enum ItemType
{
None = 0,
Weapon = 1 << 0, // 1
Armor = 1 << 1, // 2
Consumable = 1 << 2, // 4
QuestItem = 1 << 3, // 8
Key = 1 << 4 // 16
}
public ItemType properties;
void Start()
{
// 특정 아이템 타입이 포함되어 있는지 확인
if (properties.HasFlag(ItemType.Weapon))
{
Debug.Log("이 아이템은 무기입니다.");
}
if (properties.HasFlag(ItemType.QuestItem))
{
Debug.Log("이 아이템은 퀘스트 아이템입니다.");
}
}
}
이 스크립트를 유니티 오브젝트에 추가하면 Properties 필드가 체크박스 형태로 나타나 여러 ItemType을 동시에 선택할 수 있습니다. 예를 들어, Weapon과 Consumable을 동시에 체크하여 "소모품 무기"와 같은 아이템 속성을 정의할 수 있습니다.
유니티 환경에서 열거형은 게임의 다양한 시스템 (예: UI 요소의 상태, 애니메이션 전환 조건, 플레이어 입력 종류, AI의 행동 패턴 등)을 명확하고 효율적으로 관리하는 데 필수적인 도구입니다. 이처럼 유니티와 C# 열거형은 서로 시너지를 발휘하여 더욱 견고하고 유지보수하기 쉬운 게임 개발을 가능하게 합니다.
열거형은 C# 프로그래밍에서 매우 기본적이면서도 강력한 기능입니다. 단순히 상수를 묶는 것을 넘어, 코드의 의미를 풍부하게 하고, 개발 과정에서 발생할 수 있는 여러 종류의 오류를 미연에 방지하며, 장기적인 관점에서 코드의 유지보수 비용을 절감하는 데 크게 기여합니다. 특히 유니티와 같은 게임 엔진 환경에서는 직관적인 인터페이스 제공과 함께 개발 생산성을 극대화하는 중요한 요소로 작용합니다.
'c#' 카테고리의 다른 글
c# 전처리기는 컴파일 전에 소스 코드를 변형하는 지시문 (1) | 2025.07.11 |
---|---|
c# 변수와 상수의 설명 (4) | 2025.07.10 |
C# yield: 지연 실행으로 효율성을 높이는 방법 (2) | 2025.07.07 |
C# 구조체(Struct) 심층 분석: 값 형식의 핵심 (0) | 2025.07.01 |
C# while 반복문: 조건이 참인 동안 반복하다 (1) | 2025.06.30 |