Effective C# 개정판 3판 | 29장 Collection 을 반환하기보다 Iterator 를 반환하는 것이 낫다.

1. 참조



2. 소개

  • 메서드를 작성하다 보면 단일의 객체를 반환하기 보다 일련의 시퀀스를 반환해야 하는 경우가 종종 있습니다.
  • 시퀀스를 반환하는 메서드를 작성해야 한다면 컬렉션을 반환하기보다는 이터레이터를 반환하는 것이 더 좋습니다.
    • 시퀀스(sequence) : 데이터에 순서를 붙여 나열한 것

  • 이터레이터를 반환하면 이를 이용하여 다양한 작업을 좀 더 수월하게 수행할 수 있기 때문입니다.


3. 이터레이터 메서드(iterator method)

  • 이터레이터 메서드(iterator method)호출자가 요청한 시퀀스를 생성하기 위해 **yield return 문을 사용하는 메서드를 말합니다.**
  • 다음 예제에서 DaysOfTheWeek 클래스는 IEnumerable 인터페이스를 구현하며, GetEnumerator 메서드가 필요합니다.
  • 컴파일러는 GetEnumerator 메서드를 암시적으로 호출하며, IEnumerator 가 반환됩니다.
  • GetEnumerator 메서드는 yield return 문을 사용하여 각 문자열을 한 번에 하나씩 반환합니다.
using System;
using System.Collections;

namespace chapter29
{
    class Program
    {
        static void Main(string[] args)
        {
            DaysOfTheWeek days = new DaysOfTheWeek();

            foreach (var day in days)
            {
                Console.WriteLine(day + " ");
            }
        }
    }

    public class DaysOfTheWeek : IEnumerable
    {
        private string[] days = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
        public IEnumerator GetEnumerator()
        {
            for(int idx = 0; idx < days.Length; idx++)
            {
                // Yield each day of the week
                yield return days[idx];
            }
        }
    }
}
  • 이터레이터 메서드가 호출되면 컴파일러가 생성한 객체가 인스턴스화 됩니다.
  • 이후 시퀀스 내에 포함된 항목을 요청하면 비로소 시퀀스가 생성됩니다.
  • 이러한 동작 방식은 시퀀스의 크기가 작은 경우에는 별다를 바가 없습니다.
  • 그렇다면 Enumerable.Range() 를 사용하여 int 타입으로 표현 가능한 0을 포함한 양의 정수의 시퀀스를 모두 요청하는 경우를 생각해 보겠습니다.
var allNumbers = Enumerable.Range(0, int.MaxValue);
  • 이 메서드를 호출하면 숫자 시퀀스를 만들어내는 객체를 생성합니다.
  • 호출 측에서는 이터레이터 메서드의 결과값을 추가적인 컬렉션에 저장하지 않는 이상 방대한 결과치를 저장하기 위한 공간이 필요하지 않습니다.
  • 정확히 필요한 개수의 숫자만을 생성하는 것 만큼 효율적이지는 않겠지만, 0을 포함한 양의 모든 정수를 생성하여 저장소에 저장하는 것 보다는 낫습니다.
  • '필요할 때 생성' 이라는 전략은 이터레이터 메서드를 작성할 때 가장 중요한 전략 중 하나입니다.
  • 이터레이터 메서드는 시퀀스를 생성하는 방법을 알고 있는 객체를 생성합니다.
  • 그리고 이 객체는 실제 시퀀스에 대한 접근이 이루어지는 경우에만 사용됩니다.


4. 정리

  • 일련의 시퀀스를 반복적으로 사용하는 경우라면 시퀀스를 캐싱하는 것은 어떤가? 이러한 결정은 사용자가 결정하도록 남겨두는 것이 좋습니다.
  • 우리가 작성한 코드를 사용자들이 어떻게 사용할지에 대해서 섣불리 예단하면 안됩니다.
  • 실제로 ToList(), ToArray() 와 같은 확장 메서드를 통해 IEnumerable<T> 타입을 이용하는 시퀀스로부터 모든 항목이 담긴 컬렉션을 손쉽게 생성할 수 있습니다.
  • 따라서 IEnumerable<T> 을 반환하도록 메서드를 작성하면 전체 값을 가져오는 것이 효율적인 경우나 반대로 필요한 시점에 맞춰 값을 가져오는 것이 효율적인 경우에 모두에 손쉽게 대응할 수 있습니다.


728x90

이 글을 공유하기

댓글

Designed by JB FACTORY