메서드를 통해 반환한 값을 전달받을 때, 한번에 전달받을 수 없을만큼 많은 양을 분할해서 전달받거나, 호출받을 때 마다 다른 값을 전달받고싶을 때가 있다.
IEnumerable과 yield를 통해 이러한 기능을 구현할 수 있다.
우선, IEnumerable은 배열을 순회할 수 있도록 만들어주는 인터페이스이다.
우리가 foreach를 사용하여 해당하는 배열의 값을 순회하며 접근할 수 있는 것은, foreach문에 넣은 배열이 IEnumerable이라는 인터페이스를 상속받았기 때문이다.
이는 우리가 foreach문을 자주 사용했기 때문에 와닿는, 그러나 조금은 어폐가 있는 예시이기는 하다.
본래의 IEnumerable은, 어떠한 객체를 반복할 수 있도록 만들어주는 것이다.
foreach의 배열 순회 역시, 해당 객체를 반복적으로 호출하고, 호출할 때 마다 STL의 vector 컨테이너를 다룰 때 언급했던 Iterator가 해당 객체를 순차적으로 검사하기 때문에 가능한 것이다.
위와 같이 특정 객체의 데이터를 반복하여 접근하면서 데이터를 참조하고싶을 때, 그 값의 범위가 상당히 넓어 한번에 전달받는 대신, 호출시마다 하나씩 전달받고싶을 때, yield문을 사용하면 된다.
yield문은 IEnumerable을 상속받은 객체가 반복호출될 때 상호작용하는 키워드다.
yield return과 yield break가 있는데,
우선 yield return은, 호출될 때 마다 위에서부터 순서대로 값을 반환하는 내용이다.
아래는 yield return 작동의 이해를 돕기위한 코드이다.
public static IEnumerable<int> GetNumber()
{
yield return 10; // 처음 호출시 10 반환
yield return 20; // 그 다음 호출시 20 반환
yield return 30; // 그 다음 호출시 30 반환
yield return 40; // ...
yield return 50;
}
위와같이, IEnumerable을 상속받은 메서드가 호출될 때 마다 값을 다르게 반환한다.
실행 순서는 맨 위에 작성한 yield return부터 실행되며, 해당 yield return이 실행되면 다음 호출될 때는 실행되지 않고, 다음 yield return문으로 넘어가게된다.
yield break는 IEnumerable을 상속받은 메서드의 호출을 탈출시킨다.
public static IEnumerable<int> GetNumber()
{
yield return 10; // 처음 호출시 10 반환
yield return 20; // 그 다음 호출시 20 반환
yield return 30; // 그 다음 호출시 30 반환
yield break; // 아래의 코드는 더 진행되지 않음
yield return 40; // 다시 호출해도 실행되지 않음
yield return 50;
}
위처럼 GetNumber를 반복하여 호출할 때, 4회 호출시에 yield break를 만난다면, 해당 메서드는 호출이 중단된다.
예를 들면, 일반 메서드에서 return을 만나면 그 아래의 있는 코드가 작동을 하지 않듯, IEnumerable도 반복호출 중 yield break를 만나면 실행을 중단하고 빠져나간다.
public static IEnumerable<int> UntilPlus(IEnumerable<int> numbers)
{
foreach (int i in numbers)
{
if (i > 0)
yield return i;
else
yield break;// 음수가 나오면 탈출해 반복기가 더는 호출되지 않음
}
}
public static void Test()
{
foreach (var i in UntilPlus(new int[5] { 1, 3, 5, -1, 4 }))
Console.WriteLine($"{i}, ");
}
static void Main(string[] args)
{
Test();
// 출력값 : 1, 3, 5
}
위 코드는 yield문과 IEnumerable 메서드의 예제이다.
위의 UntilPlus에서, 전달받은 int형 배열의 값을 순회하며 배열의 값을 반환하다가, 음수의 값을 만나면 yield break로 반복을 멈추도록 작성했다.
Test 함수에서, 1, 3, 5, -1, 4 의 값을 저장한 배열을 전달했을 때, iterator가 배열의 값을 순차적으로 순회하다 -1을 만나 yield break가 실행되어 5까지만 출력하고 반복을 탈출했다.
IEnumerable과 yield는 기존에 논리연산자를 통한 while문 혹은 for문의 반복기준을, 컬렉션의 값으로 설정시킬 수 있어 구체적인 반복진행 및 중단은 물론, 해당 컬렉션의 값으로 반복의 기준이되는 대상을 축소시킬 수 있어 더욱 능동적이고 자율적인 반복문의 제어를 가능하게 한다.
또한, 메서드에서 한번에 전달받기 어려운 많은 량의 데이터를 순차적으로 전달받을 수 있으며, 전달받는 값의 순서도 능동적으로 설정할 수 있다.
'C# 일기' 카테고리의 다른 글
| 25. Queue (2) | 2024.03.12 |
|---|---|
| 24. Stack (0) | 2024.03.12 |
| 22. this와 this생성자 this() (0) | 2024.03.12 |
| 21. 일반화 대리자 Func VS Action (0) | 2024.03.12 |
| 20. 람다식(Lambda Expression) (0) | 2024.03.11 |