C#

[C#] IEnumerator, IEnumerable과 yield에 대해.

Binceline 2017. 2. 8. 04:39


유니티의 코루틴을 사용하게 되면서.. 어쩌다보니 알아보게 되었다.




목적

- 객체를 C++의 Iterator와 비슷하게 사용하기 위한 것이다.



IEnumerable과 IEnumerator 인터페이스 정의

- MSDN 참고 : https://msdn.microsoft.com/ko-kr/library/65zzykke(v=vs.100).aspx

public interface IEnumerable

{

    IEnumerator GetEnumerator();

}


public interface IEnumerator

{

    object Current { get; }

    bool MoveNext();

    void Reset();

}

yield return [x] : 현재 상태 저장후 값 반환

yield break : 루프 탈출

-> yield MSDN 참고 : https://msdn.microsoft.com/ko-kr/library/9k7k7cf0.aspx


IEnumerable은 단순히 IEnumerator GetEnumerator() 함수를 구현하도록 요구하는 인터페이스이다.


그리고, foreach 키워드를 사용하기 위해서는 IEnumerable을 상속받은 클래스여야 한다.


즉, 어느 클래스이든 저 IEnumerable을 상속받아 GetEnumerator() 함수를 구현한 클래스는 


내부 데이터를 foreach 같은 것으로 열거할 수 있도록 해 준다는 것이다.


아래의 예제와 같이 직접 IEnumerator 인터페이스를 구현해 바꿔치기하는 식으로 직접 구현해야 하지만,


yield 키워드를 사용해서 IEnumerator나 IEenumerable 형으로 값을 반환하면 그럴 필요가 없다.


yield를 사용하게 되면, 루프 안에서 현재 상태를 기억하고, 값을 하나씩 반환시키게 된다.

= 특정 상황에 따라 부하를 줄일 수 있다.




원문(MSDN) : https://msdn.microsoft.com/ko-kr/library/system.collections.ienumerator(v=vs.110).aspx

예제

using System;
using System.Collections;

// Simple business object.
public class Person
{
    public Person(string fName, string lName)
    {
        this.firstName = fName;
        this.lastName = lName;
    }

    public string firstName;
    public string lastName;
}

// Collection of Person objects. This class
// implements IEnumerable so that it can be used
// with ForEach syntax.
public class People : IEnumerable
{
    private Person[] _people;
    public People(Person[] pArray)
    {
        _people = new Person[pArray.Length];

        for (int i = 0; i < pArray.Length; i++)
        {
            _people[i] = pArray[i];
        }
    }

// Implementation for the GetEnumerator method.
    IEnumerator IEnumerable.GetEnumerator()
    {
       return (IEnumerator) GetEnumerator();
    }

    public PeopleEnum GetEnumerator()
    {
        return new PeopleEnum(_people);
    }
}

// When you implement IEnumerable, you must also implement IEnumerator.
public class PeopleEnum : IEnumerator
{
    public Person[] _people;

    // Enumerators are positioned before the first element
    // until the first MoveNext() call.
    int position = -1;

    public PeopleEnum(Person[] list)
    {
        _people = list;
    }

    public bool MoveNext()
    {
        position++;
        return (position < _people.Length);
    }

    public void Reset()
    {
        position = -1;
    }

    object IEnumerator.Current
    {
        get
        {
            return Current;
        }
    }

    public Person Current
    {
        get
        {
            try
            {
                return _people[position];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}

class App
{
    static void Main()
    {
        Person[] peopleArray = new Person[3]
        {
            new Person("John", "Smith"),
            new Person("Jim", "Johnson"),
            new Person("Sue", "Rabon"),
        };

        People peopleList = new People(peopleArray);
        foreach (Person p in peopleList)
            Console.WriteLine(p.firstName + " " + p.lastName);

    }
}

/* This code produces output similar to the following:
 *
 * John Smith
 * Jim Johnson
 * Sue Rabon
 * 

 */


yield 키워드 사용 예

    public class PowersOf2
    {
        static void Main()
        {
            // Display powers of 2 up to the exponent of 8:
            foreach (int i in Power(2, 8))
            {
                Console.Write("{0} ", i);
            }
        }

        public static System.Collections.Generic.IEnumerable<int> Power(int number, int exponent)
        {
            int result = 1;

            for (int i = 0; i < exponent; i++)
            {
                result = result * number;
                yield return result;
            }
        }

        // Output: 2 4 8 16 32 64 128 256
    }


읽어볼 거리로 좋은 글을 추천한다.. 

참고글 : https://csharpschoolblog.wordpress.com/2016/10/16/ienumerator-ienumerable의-의미

반응형