IEnumerator 와 yield return 은 이해가 완벽히 되지 않더라도 사용하는데는 크게 지장이 없습니다.
다만, 이게 왜 이렇게 될까 ? 기존 문법에도 안맞는것 같고 ... 그러다보면 코드가 잘 눈에 안들어옵니다.
그러다보니, 내용이 좀 길어졌습니다.
그리고 아직 다 전달하지 못한 내용들은 여기에 두서없이 적어놓겠습니다.
보충편 : 코루틴과 IEnumerator의 숨겨진 개념들
이전 글에서는 코루틴의 기본적인 개념과 활용법을 다루었습니다. 하지만 코루틴을 배우면서 헷갈릴 수 있는 개념들이 몇 가지 있습니다. 이번 보충편에서는 그동안 다루지 못했던 중요한 개념들을 정리해 보겠습니다.
IEnumerator는 함수 호출이 곧 객체 생성이다?
코루틴을 처음 배울 때 가장 헷갈릴 수 있는 개념 중 하나가 바로 인터페이스는 new로 객체를 생성할 수 없는데, 왜 IEnumerator는 함수 호출만으로 객체가 생성되는가? 입니다.
예를 들어, 일반적으로 클래스 객체를 생성하려면 new 키워드를 사용해야 합니다.
MyClass obj = new MyClass();
하지만 IEnumerator를 반환하는 함수는 new 없이도 객체를 생성할 수 있습니다.
IEnumerator enumerator = MyCoroutine();
이게 가능한 이유는 C# 컴파일러가 yield return이 포함된 함수를 IEnumerator 를 구현하는 클래스 객체로 변환하기 때문입니다. 즉, IEnumerator 함수는 실행될 때마다 새로운 객체를 반환하는 "객체 생성 함수" 가 됩니다.
IEnumerator 함수 내부적으로 변환되는 코드 예시
class MyCoroutineState : IEnumerator
{
private int state = 0;
public object Current { get; private set; }
public bool MoveNext()
{
switch (state)
{
case 0:
Current = null;
state = 1;
return true;
case 1:
state = -1;
return false;
}
return false;
}
public void Reset() { state = 0; }
}
이처럼 IEnumerator를 반환하는 함수는 컴파일러에 의해 내부적으로 클래스로 변환되면서, 함수가 실행될 때마다 새로운 IEnumerator 객체가 생성됩니다.
yield return은 왜 반드시 IEnumerator 내부에서만 사용 가능한가?
yield return은 일반적인 void 함수에서는 사용할 수 없습니다. 아래 코드처럼 void 함수에서 yield return을 사용하면 컴파일 오류가 발생합니다.
void MyFunction()
{
yield return null; // 오류 발생
}
이는 yield return이 단순한 반환문이 아니라, 실행 상태를 저장하는 기능을 수행하기 때문입니다. 일반적인 함수에서는 실행 상태를 저장할 방법이 없지만, IEnumerator를 반환하는 함수는 상태를 저장할 수 있습니다.
즉, yield return은 실행 중단과 재개를 관리하기 위해 반드시 IEnumerator 내부에서만 사용 가능합니다.
yield return과 foreach의 관계
yield return을 사용하면 foreach 에서 사용할 수 있는 반복자(Enumerator) 를 쉽게 만들 수 있습니다.
IEnumerable<int> GetNumbers()
{
yield return 1;
yield return 2;
yield return 3;
}
foreach (int num in GetNumbers())
{
Console.WriteLine(num);
}
위 코드에서 GetNumbers() 함수는 yield return을 사용하여 실행을 멈추면서 값들을 하나씩 반환합니다. 그리고 foreach문은 IEnumerator의 MoveNext()를 호출하면서 반복을 수행합니다.
yield return을 활용한 상태 머신 (State Machine)
코루틴은 상태를 유지하는 기능이 있기 때문에, 상태 머신을 구현하는 데도 활용될 수 있습니다.
IEnumerator StateMachine()
{
Debug.Log("대기 상태");
yield return new WaitForSeconds(2f);
Debug.Log("이동 상태");
yield return new WaitForSeconds(3f);
Debug.Log("공격 상태");
}
이 코루틴을 실행하면 각 상태에서 일정 시간 동안 멈췄다가 다음 상태로 넘어가는 동작을 할 수 있습니다.
마무리
IEnumerator를 반환하는 함수는 "객체 생성 함수" 로 동작하며, 실행될 때마다 새로운 IEnumerator 객체가 생성된다.
yield return 은 실행 상태를 저장해야 하기 때문에, IEnumerator를 반환하는 함수 내에서만 사용 가능하다.
yield return 을 사용하면 foreach에서 사용할 수 있는 반복자를 쉽게 만들 수 있다.
yield return 을 활용하여 상태 머신을 만들 수 있다.
이번 보충편에서는 그동안 다루지 못했던 중요한 개념들을 정리했습니다.
'C#' 카테고리의 다른 글
전역으로 관리되는 class 를 만들고 싶을 때 (singleton) (0) | 2025.03.10 |
---|---|
Vector3 pos = new Vector3() 의 이해와 대안 (0) | 2025.03.10 |
7. yield return 에 대해 ( 최종화 : 최적화 ) (0) | 2025.03.09 |
6. yield return 에 대해 ( Coroutine 을 중지하고자 할 때 ) (0) | 2025.03.09 |
5. yield return 에 대해 ( 활용 02 ) (0) | 2025.03.09 |