Effective C# 개정판 3판 | 33장 필요한 시점에 필요한 요소를 생성하라.

1. 참조

  • Effective C# 개정판 3판


2. 소개

  • Iterator Method 가 입력 변수로 반드시 Sequence 를 받을 필요는 없습니다.
  • 작업을 수행하기 전에 필요한 요소를 모두 생성해서 Collection 에 저장해두는 대신 필요할 때마다 개발 요소를 생성하는 식입니다.
  • 이 방법으로 코드를 작성하면 사용 되지 않을 요소를 미리 생성하는 것을 피할 수 있습니다.


3.1 정수값의 Sequence 생성

3.2 일반 Collection 예제 코드

using System;
using System.Collections.Generic;

namespace Chapter33
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = CreateSequence(5, 1, 0);

            foreach (var item in result)
            {
                Console.WriteLine($"value : {item}");
            }
        }

        static IList<int> CreateSequence(int numberOfElements, int startAt, int stepBy)
        {
            var collection = new List<int>(numberOfElements);

            for(int idx =0; idx < numberOfElements; idx++)
            {
                collection.Add(startAt + idx + stepBy);
            }

            return collection;
        }
    }
}

3.3 실행 결과

value : 1
value : 2
value : 3
value : 4
value : 5
  • 위의 코드는 잘 동작하지만 yield return 을 이용하여 새로운 시퀀스를 생성하는 것에 비하여 단점이 많습니다.
  • 우선 위의 코드는 결과를 List<int> 에 저장한다고 가정하고 있습니다.
  • 클라이언트가 BindingList<int> 와 같이 다른 타입을 요구하면 변환 작업을 반드시 수행해야 합니다.
  • 이처럼 변환을 수행하면 그 과정에서 미묘한 버그가 발생할 소지가 있습니다.
  • 또한, 클라이언트가 중간에 작업을 중단할 수 없기 떄문에 CreateSequence() 메서드는 항상 요청된 개수 만큼 요소를 생성합니다.
  • Sequence를 생성하는 기능을 Iterator Method로 만들면 위와 같은 문제들을 피할 수 있습니다.

3.4 yield return 이용한 예제 코드

using System;
using System.Collections.Generic;

namespace Chapter33
{
    class Program
    {
        static void Main(string[] args)
        {
            var result = CreateSequence(5, 1, 0);

            foreach (var item in result)
            {
                Console.WriteLine($"Value : {item}");
            }
        }

        static IEnumerable<int> CreateSequence(int numberofElements, int startAt, int stepBy)
        {
            for(int idx = 0; idx < numberofElements; idx++)
            {
                yield return startAt + idx + stepBy;
            }
        }
    }
}

3.5 실행 결과

value : 1
value : 2
value : 3
value : 4
value : 5
  • 위와 같이 새로게 작성한 코드를 실행하면 Sequence 내의 개별 요소가 요청 시마다 하나씩 생성됩니다.
  • 동일한 int 타입의 요소를 생성하기 때문에 코드를 위처럼 수정해도 작업의 내용은 변경되지 않습니다.
  • 그리고 이 코드는 어떤 Collection에 저장하더라도 문제없이 동작합니다.
  • 또한, 조건에 부합하지 않는 상황이 됐을 때 추가로 숫자를 생성하지 않으므로 2.2 예제 코드에 비해서 성능상의 이점이 있습니다.


4. 정리

  • Sequence를 소비하는 측에서 값을 요청하는 시점에 맞춰 필요한 값을 생성하는 것이 가장 좋습니다.
  • Sequence 전체를 소비하지 않고 일부만 필요한 경우임에도 전체 요소를 미리 생성해 두는 것은 좋은 방법이 아닙니다.
  • 어떤 경우라도 필요한 시점에 맞춰 필요한 요소를 생성하도록 코딩하는 것이 가장 효과적입니다.
  • yield return 구문을 자주 사용하길 권장합니다.


728x90

이 글을 공유하기

댓글

Designed by JB FACTORY