C# 팁: yield return을 사용하여 한 번에 하나의 항목 반환

10147 단어 csharpdotnet
나에게 yield return는 항상 이해하기 가장 어려운 것 중 하나였습니다.

이제 내가 그것을 이해했으므로(완전하지는 않지만 설명하기에 충분함) 이제 내가 배운 것을 공유할 차례입니다.

그렇다면 yield return는 무엇을 의미합니까? 항목 컬렉션과 어떤 관련이 있습니까?

목록 사용



항목 컬렉션을 반환하고 있으며 항목을 반복해야 한다고 가정해 보겠습니다.

첫 번째 접근 방식은 모든 항목이 포함된 목록을 만들어 호출자에게 반환하고 컬렉션을 반복하는 것입니다.

IEnumerable<int> WithList()
{
    List<int> items = new List<int>();

    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine($"Added item {i}");
        items.Add(i);
    }

    return items;
}

void Main()
{
    var items = WithList();

    foreach (var i in items)
    {
        Console.WriteLine($"This is Mambo number {i}");
    }
}


이 스니펫은 전체 컬렉션을 생성한 다음 해당 목록 내의 값을 인쇄합니다. 콘솔에 다음 텍스트가 표시됩니다.

Added item 0
Added item 1
Added item 2
Added item 3
Added item 4
Added item 5
Added item 6
Added item 7
Added item 8
Added item 9
This is Mambo number 0
This is Mambo number 1
This is Mambo number 2
This is Mambo number 3
This is Mambo number 4
This is Mambo number 5
This is Mambo number 6
This is Mambo number 7
This is Mambo number 8
This is Mambo number 9


즉, 100만 개의 항목이 있는 컬렉션에 대해 작업을 수행해야 하는 경우 먼저 모든 항목을 만든 다음 각 항목에 대해 작업을 수행합니다. 이 접근 방식에는 두 가지 주요 단점이 있습니다. 속도가 느리고(특히 해당 항목의 하위 집합으로만 작업해야 하는 경우) 많은 메모리를 차지합니다.

수율로



다른 접근 방식을 사용할 수 있습니다. yield return 키워드를 사용합니다.

IEnumerable<int> WithYield()
{
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine($"Returning item {i}");

        yield return i;
    }
}

void Main()
{
    var items = WithYield();

    foreach (var i in items)
    {
        Console.WriteLine($"This is Mambo number {i}");
    }
}


이 방법을 사용하면 메시지 순서가 다릅니다.

Returning item 0
This is Mambo number 0
Returning item 1
This is Mambo number 1
Returning item 2
This is Mambo number 2
Returning item 3
This is Mambo number 3
Returning item 4
This is Mambo number 4
Returning item 5
This is Mambo number 5
Returning item 6
This is Mambo number 6
Returning item 7
This is Mambo number 7
Returning item 8
This is Mambo number 8
Returning item 9
This is Mambo number 9


따라서 전체 목록을 만드는 대신 필요할 때만 한 번에 하나의 항목을 만듭니다.

수율의 이점



이전에 말했듯이 yield에는 몇 가지 이점이 있습니다. 실행 시간과 메모리 사용량 모두에 대해 이야기할 때 응용 프로그램의 성능이 향상됩니다.

자동 반복기와 같습니다. 결과를 얻을 때마다 반복자가 다음 항목으로 이동합니다.

참고: yieldIAsyncEnumerable<T> , IEnumerable<T> , IEnumerable , IEnumerator<T> 또는 IEnumerator 를 반환하는 메서드에서만 작동합니다.

예를 들어 List<T>를 반환하는 메서드와 함께 사용할 수 없습니다.

The body of X cannot be an iterator block because List<int> is not an iterator interface type





실제 사용 사례



NUnit을 테스트 스위트로 사용한다면 이미 이 키워드를 사용했을 것입니다.

특히 TestCaseSource 속성을 사용할 때 테스트 케이스를 출력하는 클래스의 이름을 지정합니다.

public class MyTestClass
{
    [TestCaseSource(typeof(DivideCases))]
    public void DivideTest(int n, int d, int q)
    {
        Assert.AreEqual(q, n / d);
    }
}

class DivideCases : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        yield return new object[] { 12, 3, 4 };
        yield return new object[] { 12, 2, 6 };
        yield return new object[] { 12, 4, 3 };
    }
}


테스트를 실행할 때 반복자는 전체 테스트 사례 목록을 만들지 않고 한 번에 테스트 사례를 반환합니다.

이전 스니펫은 TestCaseSource 속성, that you can find here 에 대한 NUnit의 문서에서 직접 가져온 것입니다.

마무리



네, yield는 상당히 이해하기 어려운 키워드입니다.

자세한 내용을 보려면 the official docs으로 이동하십시오.

또 다른 좋은 리소스는 "C# – Use yield return to minimize memory usage" by . 당신은 확실히 그것을 확인해야합니다!

원하는 경우 이 키워드에 대해 나눈 대화를 확인하세요.

즐거운 코딩하세요!

🐧

좋은 웹페이지 즐겨찾기