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

10157 단어 dotnetcsharp
나에게 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 . 반드시 확인하셔야 합니다!

그리고 원한다면 이 키워드에 대해 나눈 대화를 확인하십시오.

즐거운 코딩!

🐧

좋은 웹페이지 즐겨찾기