멈추지 않고 끈질기게
[C#] 열거형(Enum) 본문
※ 해당 포스팅은 개인의 공부 정리용 글입니다. 틀린 내용이 있다면 추후 수정될 수 있습니다.
※ 해당 포스팅은 .Net 7.0 버전을 기준으로 작성되었습니다.
※ 해당 포스팅은 하기 출처들을 참조하였습니다.
- https://learn.microsoft.com/ko-kr/dotnet/csharp/language-reference/builtin-types/enum
- https://www.csharpstudy.com/CSharp/CSharp-enum.aspx
1. 열거형(enum)
열거형은 정수 형태의 값들을 별도의 이름으로 정의해 둔 상수들의 집합으로, C#에서는 다음과 같이 enum 키워드를 사용하고 내부에 열거형 멤버들을 선언하여 정의합니다.
enum Direction
{
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
기본적으로 열거형 멤버들의 타입은 int형이며, 값을 따로 지정해주지 않는다면 첫번째 멤버는 0에서 시작하고 이후로는 순서대로 1씩 증가합니다. 위 예시의 경우 Up = 0, Down = 1, Left = 2, Right = 3 이 됩니다.
enum Item : long // 멤버 타입 지정
{
None = -1,
Usable = 1,
Weapon = 10,
Armor, // = 11
ForQuest = 100
}
위와 같이 열거형 멤버들의 타입을 따로 지정해줄 수 있고, 각 멤버의 값도 별도로 지정해줄 수 있습니다. 중간에 값을 따로 지정해주지 않은 멤버는 그 이전의 멤버 값에서 1 증가한 값으로 자동으로 지정됩니다. 위 예시의 경우 Item.Armor의 값은 바로 이전 멤버 Item.Weapon의 값에서 1 증가하여 11이 됩니다.
또한 열거형을 비트 플래그 형식으로 정의할 수도 있습니다. 이 경우, 각 멤버 값들 간에 중복되는 비트가 없도록 정의해야 합니다. 열거형을 비트 플래그 형식으로 선언한 경우, 해당 열거형 타입의 변수에 비트 연산자(&, | 등)를 활용할 수 있습니다.
// 비트 플래그 형식의 열거형
// 각 멤버 값에서 중복되는 비트가 없도록 선언
[Flags]
enum Direction
{
None = 0, // 0b_0000_0000
North = 1, // 0b_0000_0001
South = 2, // 0b_0000_0010
East = 4, // 0b_0000_0100
West = 8, // 0b_0000_1000
}
static void Main(string[] args)
{
// 0b_0000_1001
Direction myDir = Direction.North | Direction.West;
// 비트 연산자 &를 통한 검사
if((myDir & Direction.North) != 0)
{
if ((myDir & Direction.West) != 0)
{
Console.WriteLine("현재 방향은 북서쪽입니다.");
}
}
// HasFlag() 함수를 통한 검사
if(myDir.HasFlag(Direction.North))
{
if(myDir.HasFlag(Direction.West))
{
Console.WriteLine("현재 방향은 북서쪽입니다.");
}
}
}
위는 비트 플래그 형식의 열거형을 사용하는 예시입니다. Direction 열거형을 비트 플래그 형식으로 정의하고, Direction 타입의 변수 myDir을 (Direction.North | Direction.West)로 초기화 하였습니다(0b_0000_1001). 해당 변수에 & 연산자를 통해
Direction.North 및 Direction.West값을 포함하는지 검사한 후, 둘 다 있다면 북서쪽임을 출력하도록 했습니다.
또한 HasFlag() 함수를 통해 해당 비트를 포함하는지 검사할 수도 있습니다. 아래쪽 조건문에서는 HasFlag()를 통해 Direction.North 및 Direction.West값을 포함하는지 검사한 후, 둘 다 있다면 북서쪽임을 출력하도록 했습니다.
2. 열거형을 사용하는 이유
열거형을 사용하면 상수를 사용하는 코드의 가독성을 크게 향상시킬 수 있습니다. 다음은 int형 매개변수를 받는 함수의 예시입니다.
public static class Test
{
// 0: 북쪽, 1: 남쪽, 2:동쪽, 3:서쪽
public static void DirectionCheck(int direction)
{
switch(direction)
{
case 0:
// 북쪽 방향일 경우
break;
case 1:
// 남쪽 방향일 경우
break;
case 2:
// 동쪽 방향일 경우
break;
case 3:
// 서쪽 방향일 경우
break;
}
}
}
class Program
{
static void Main(string[] args)
{
Test.DirectionCheck(1); // ???
}
}
int형 매개변수를 받은 후 해당 값에 따라 방향에 따른 동작을 실행하는 함수 DirectionCheck()를 선언하고, 메인 함수에서 해당 함수를 실행하도록 했습니다. 메인 함수 내부만 보면 매개변수 1이 도대체 어떤 뜻인지 이해하기 어렵습니다. 다른 사람이 이해할 수 있도록 하려면 해당 함수를 호출하는 부분마다 매번 주석을 달아야 할 것입니다. 그렇다고 DirectionCheck() 함수의 매개변수 타입을 string 타입으로 바꾸었다간 되려 오탈자로 인한 실행 오류 등에 취약해질 것입니다.
public enum Direction
{
North,
South,
East,
West
}
public static class Test
{
// 0: 북쪽, 1: 남쪽, 2:동쪽, 3:서쪽
public static void DirectionCheck(Direction direction)
{
switch(direction)
{
case Direction.North:
// 북쪽 방향일 경우
break;
case Direction.South:
// 남쪽 방향일 경우
break;
case Direction.East:
// 동쪽 방향일 경우
break;
case Direction.West:
// 서쪽 방향일 경우
break;
}
}
}
class Program
{
static void Main(string[] args)
{
Test.DirectionCheck(Direction.South); // 남쪽
}
}
이런 경우에 간단하게 Direction이라는 열거형을 선언한 뒤, DirectionCheck()에서 해당 열거형 타입의 매개변수를 받도록 하면 됩니다. 이제 메인 함수에서 호출하는 부분만 봐도 남쪽을 확인한다는 것을 단번에 알 수 있습니다. 혹은 int형 매개변수를 받는 함수라면, Convert.ToInt32() 함수를 통해 열거형 멤버 값을 int형으로 전달할 수도 있습니다.
3. 포트폴리오 내 예제
하기 코드들은 개발중인 유니티 3D 포트폴리오 프로젝트에서 사용중인 열거형 사용 예시입니다.
// GameManager 클래스
// 현재 게임 상태
public enum GameMode
{
NotConnected,
Lobby,
SingleGame,
MultiGame
}
GameMode curMode;
public GameMode CurMode { get { return curMode; } }
// ------------------------------------------------------
public void PlayerExit()
{
// 멀티 플레이 시 처리
// 나머지 플레이어들에게 생존자 -1 카운트
if(curMode == GameMode.MultiGame)
PV.RPC(nameof(Survive_Minus), RpcTarget.Others);
// 로비 이동
SceneController.Instance.ExitStage();
curMode = GameMode.Lobby;
// 일시정지 및 변수 초기화
isPaused = false;
}
GameManager 클래스에서는 현재 게임 상태를 구분하기 위해 열거형 GameMode를 정의하고 해당 열거형 타입 변수 curMode를 선언하였으며, curMode를 반환하는 속성을 선언하여 외부 클래스에서 현재 게임 상태를 확인할 수 있도록 하였습니다.
또한 플레이어가 게임 중간에 퇴장하는 경우 호출하는 PlayerExit() 함수의 경우, 현재 멀티 플레이 중이라면 나머지 인원들에게 생존자 카운트를 -1 하는 함수를 호출하도록 했습니다. 'curMode == GameMode.MultiGame'와 같이 열거형 변수를 통해 체크하여 어떤 내용인지 한눈에 들어오도록 했습니다.
// 애니메이터 변수 관리용
enum AnimatorVar
{
isMoving,
isJumping,
doSlide,
isGrapping,
onKnockBack
}
// ------------------------------------------------
void Slide()
{
// 열거형을 이용해 호출
animator.SetTrigger(AnimatorVar.doSlide.ToString());
rigid.AddForce(moveVec.normalized * slidePower, ForceMode.Impulse);
curState = CurState.IsSliding;
StageSoundController.PlaySfx((int)StageSoundController.StageSfx.jump);
}
Player 클래스에서는 애니메이터의 bool, trigger 변수들 이름을 열거형 멤버로 정의해 두었습니다. 애니메이터의 SetBool(), SetTrigger() 함수가 변수 이름을 string 타입으로 받기 때문에, 직접 문자열을 입력하는 대신 열거형 멤버를 ToString()으로 문자열로 변환하여 전달하도록 작성했습니다. 이렇게 하면 문자열을 매 호출마다 직접 입력하지 않아도 되고, 열거형 멤버의 이름만 오탈자가 없도록 체크한다면 오탈자로 인해 애니메이션이 제대로 실행되지 않는 상황을 예방할 수 있습니다.
'C#' 카테고리의 다른 글
[C#] Thread, ThreadPool, Task (0) | 2023.10.26 |
---|---|
[C#] C# 9.0 기능(record 타입, 초기화 전용 속성(init), 타겟 타이핑(new(), 조건 연산자)) (0) | 2023.10.09 |
[C#] 형변환 함수 / 연산자 (0) | 2023.06.01 |
[C#] StringBuilder (0) | 2023.02.20 |
[C#] 가비지 컬렉터(Garbage Collector) (0) | 2023.02.20 |