Notice
Recent Posts
Recent Comments
Link
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags
more
Archives
Today
Total
관리 메뉴

물에 사는 벌레

C#의 IEnumerator에 대해 알아보자 본문

C#

C#의 IEnumerator에 대해 알아보자

물벌레 2019. 7. 13. 23:06

유니티 스타일의 코루틴 구현하기에 앞서 IEnumerator를 살짝 맛보기로 한다.

이것을 사용하기 전에 먼저 System.Collection 네임스페이스를 사용해야 한다.

using System;
using System.Collections;

예제로 아주 간단한 열거자 사용을 해 보자.

	static IEnumerator TestIEnumerator()
        {
            Console.WriteLine("1");
            Console.WriteLine("2");
            Console.WriteLine("3");
            yield return null;
        }

        static void Main(string[] args)
        {
            IEnumerator testIEnumerator = TestIEnumerator();
            testIEnumerator.MoveNext();
        }

우선 열거자의 마지막 줄을 보면 null을 반환하는 모습을 볼 수 있다.

또한 열거자를 마치 변수처럼 대입하여 사용하는 형태가 보이며,

마지막으로 MoveNext 메서드가 등장하는데 이 메서드를 통하여 열거자를 실행시키고 있다.

 

* 참고로 MoveNext 메소드를 두 번 이상 실행하면 아무런 변화도 생기지 않습니다. 이유는 다음 코드에서 설명한다.

 

정리하자면

1. 열거자는 최소 한 개의 yield 문을 가지고 있어야 한다.

2. 열거자는 변수처럼 대입하여 사용할 수 있다.

3. MoveNext 메소드를 통해 열거자 내부의 내용을 실행할 수 있다.

 

이번에는 조금 다르게 사용해 본다.

    class Program
    {
        static IEnumerator TestIEnumerator()
        {
            Console.Write("첫 번째 반환: ");
            yield return 1;
            Console.Write("두 번째 반환: ");
            yield return 2;
            Console.Write("세 번째 반환: ");
            yield return 3;
            Console.WriteLine("반환 끝");
        }

        static void Main(string[] args)
        {
            IEnumerator testIEnumerator = TestIEnumerator();

            Console.WriteLine(testIEnumerator.Current == null ? "null" : "");

            testIEnumerator.MoveNext();
            Console.WriteLine(testIEnumerator.Current);

            testIEnumerator.MoveNext();
            Console.WriteLine(testIEnumerator.Current);

            testIEnumerator.MoveNext();
            Console.WriteLine(testIEnumerator.Current);

            testIEnumerator.MoveNext();

            // 출력
            // null
            // 첫 번째 반환: 1
            // 두 번째 반환: 2
            // 세 번째 반환: 3
            // 반환 끝
        }
    }

열거자 내부 구현이 전부 yield return ...으로 바뀌었다.

그리고 MoveNext 메소드가 여러 번 실행되며, Current 프로퍼티를 통하여 열거자의 현재 값을 출력하려는 시도가 보인다.

 

코드를 설명하자면 맨 처음 열거자의 Current는 null로 시작하여 MoveNext를 실행할 때 마다 열거자 내부의 반환값인 1, 2, 3이 순차적으로 Current에 대입되는 모습을 볼 수 있다.

 

이를 잘 알기 위해서는 yield에 대하여 알아야 하는데 그냥 반환이 아닌 yield(양보) 반환은 열거자 내에 존재할 때, MoveNext 메서드를 실행 시 마지막 반환이 있던 코드의 다음 줄 부터 마지막 반환의 다음 반환까지의 코드를 실행하게 된다.

그리고 Current 프로퍼티는 반환된 값을 가리키고 있게 된다.

 

같은 말이 여러 번 나오니 조금 헷갈리는데, 하니씩 풀어 보면 

	static IEnumerator TestIEnumerator()
        {
            Console.Write("첫 번째 반환: ");	//1
            yield return 1;	//2
            Console.Write("두 번째 반환: ");	//3
            yield return 2;	//4
            Console.Write("세 번째 반환: ");	//5
            yield return 3;	//6
            Console.WriteLine("반환 끝");	//7
        }

열거자에 대하여 MoveNext를 실행하기 전의 Current는 null이다.

이후 MoveNext를 처음 실행하면 2번째 줄 까지 코드가 실행되고 Current는 1이 된다.

다음 MoveNext 실행 시 3번 줄 부터 4번 줄 까지 실행되고 Current는 2가 된다.

또 다음 실행은 5번 줄 부터 6번 줄까지 실행되고 Current가 3이 되며,

마지막 실행에서는 7번 줄만 실행되어 반환 끝 메시지가 출력되고 Current는 여전히 3으로 유지된다.

고로 실행 순서는 1~2, 3~4, 5~6, 7 이 된다.

 

이를 활용하여 최종적으로 코드를 간단하게 줄일 수 있다.

    class Program
    {
        static IEnumerator TestIEnumerator()
        {
            yield return 1;
            yield return 2;
            yield return 3;
        }

        static void Main(string[] args)
        {
            IEnumerator testIEnumerator = TestIEnumerator();
            while(testIEnumerator.MoveNext() == true)
            {
                Console.WriteLine(testIEnumerator.Current);
            }

            // 출력
            // 1
            // 2
            // 3
        }
    }

MoveNext 메소드는 현재 yield return 줄을 기준으로 다음 코드가 존재하면 true 아니면 false를 반환한다.

이를 이용하여 코드를 다음 반환까지 실행함과 동시에 다음 코드가 존재하는지 검사도 하고 있다.

'C#' 카테고리의 다른 글

유니티 스타일의 코루틴 구현하기  (0) 2019.07.14
Comments