본문 바로가기
C#/Effective C#

[Effective C#] Item 29 컬렉션을 반환하기보다 이터레이터를 반환하는 것이 낫다.

by 코모's 2022. 11. 7.
반응형

메서드를 작성하다 보면 단일의 객체를 반환하기보다 일련의 시퀀스를 반환해야 하는 경우가 더러 있다. 시퀀스를 반환하는 메서드를 작성해야 한다면 컬렉션을 반환하기 보다는 이터레이터를 반환하는 것이 더 좋다. 이터레이터를 반환하면 이를 이용하여 다양한 작업을 좀 더 수월하게 수행할 수 있기 때문이다.

 

cf) 시퀀스(sequence) : 데이터에 순서를 붙여 나열한것

 

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

 

이터레이터 메서드란 호출자가 요청한 시퀀스를 생성하기 위해 yield return 문을 사용하는 메서드를 말한다. 다음은 알파벳 소문자에 대한 시퀀스를 생성하는 매우 기본적인 이터레이터 메서드의 구현 예를 나타내었다.

 

public static IEnumerator<char> GenerateAlphabet() 
{
    var letter = 'a'; 
    
    while (letter <= 'z') 
    {
    	yield return letter; 
        letter++; 
    }
}

이터레이터 메서드가호출되면 컴파일러가 생성한 객체가 인스턴스화 된다. 이후 시퀀스 내에 포함된 항목을 요청하면 비로소 시퀀스가 생성된다. 이러한 동작 방식은 시퀀스의 크기가 작은 경우에는 별다를바가 없다.

크렇다면 Enumerable.Range()를 사용하여 int 타입으로 표한 가능한 0을 포함한 정수의 시퀀스를 모두 요청하는 경우를 생각해보자.

 

var allNumbers = Enumerable.Range(0, int.MaxVlue);

 

이 메서드를 호출하면 숫자 시퀀스를 만들어내는 객체를 생성한다. 호출 측에서는 이터레이터 메서드의 결과값을 추가적인 컬렉션에 저장하지 않는 이상 방대한 결과치를 저장하기 위한 공간이 필요하지 않다. 정확히 필요한 개수의 숫자만을 생성하는 것만큼 효율적이지는 않겠지만 0을 포함한 양의 모든 정수를 생성하여 저장소에 저장하는 것보다는 낫다.

 

'필요할 때 생성' 이라는 전략은 이터레이터 메서드를 작성할 때 가장 중요한 전략 중 하나다. 이터레이터 메서드는 시퀀스를 생성하느 방법을 알고 있는 객체를 생성한다. 그리고 이객체는 실제 시퀀스에 대한 접근이 이루어 지는 경우에만 사용된다.

 

어떤 경우에 이터레이터 메서드르 이용하여 시퀀스르 생성하는 것이 좋은가?

 

일련의 시퀀스를 반복적으로 사용하는 경우라면 시퀀스를 캐싱하는 것은 어떤가? 이러한 결정은 사용자가 결정하도록 남겨두는 것이 좋다. 우리가 작성한 코드를 사용자들이 어떻게 사용할지에 대해서 섣불리 예단하지 말자. 

 

실제로 ToList(), ToArray() 와 같은 확장 메서드를 통해 IEnumrable<T> 타입을 이용하는 시퀀스로부터 모든 항목이 담긴 컬렉션을 손쉽게 생성할 수 있다. 따라서 IEnumerable<T>을 반환하도록 메서드를 작성하면 전체 값을 가져오는 것이 효율적인 경우나 반대로 필요한 시점에 맞춰 값을 가져오는 것이 효율적인 경우 모두 손쉽게 대응할 수있다.

 

 

 

 

참조 - Effective C# <강력한 C# 코드를 구현하는 50가지 전략과 기법, 이펙티브>, 빌 와그너, 김명신, 한빛미디어

반응형