[C#] C #에서 사용되는 yield 키워드는 무엇입니까?

IList의 단편 만 노출 하는 방법 <> 질문에서 답변 중 하나에 다음 코드 스 니펫이 있습니다.

IEnumerable<object> FilteredList()
{
    foreach(object item in FullList)
    {
        if(IsItemInPartialList(item))
            yield return item;
    }
}

yield 키워드는 무엇을합니까? 나는 그것을 두 곳에서 언급하고 다른 질문 하나를 보았지만 실제로 실제로 무엇을하는지 알지 못했습니다. 한 스레드가 다른 스레드에 양보한다는 의미에서 수율을 생각하는 데 익숙하지만 여기서는 관련이 없습니다.



답변

yield키워드는 실제로 여기에 꽤 많이한다.

이 함수는 IEnumerable<object>인터페이스 를 구현하는 객체를 반환합니다 . 호출 함수 foreach가이 오브젝트를 시작 하면 “수율”이 될 때까지 함수가 다시 호출됩니다. 이것은 C # 2.0에 도입 된 구문 설탕 입니다. 이전 버전에서는 사용자가 직접 만들어야했습니다 IEnumerableIEnumerator같은 물건을 할 객체.

이와 같은 코드를 이해하는 가장 쉬운 방법은 예제를 입력하고 중단 점을 설정하고 어떤 일이 발생하는지 확인하는 것입니다. 이 예제를 단계별로 시도하십시오.

public void Consumer()
{
    foreach(int i in Integers())
    {
        Console.WriteLine(i.ToString());
    }
}

public IEnumerable<int> Integers()
{
    yield return 1;
    yield return 2;
    yield return 4;
    yield return 8;
    yield return 16;
    yield return 16777216;
}

예제를 Integers()살펴보면 returns에 대한 첫 번째 호출이 1있습니다. 두 번째 통화가 돌아가고 2회선 yield return 1이 다시 실행되지 않습니다.

실제 예는 다음과 같습니다.

public IEnumerable<T> Read<T>(string sql, Func<IDataReader, T> make, params object[] parms)
{
    using (var connection = CreateConnection())
    {
        using (var command = CreateCommand(CommandType.Text, sql, connection, parms))
        {
            command.CommandTimeout = dataBaseSettings.ReadCommandTimeout;
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    yield return make(reader);
                }
            }
        }
    }
}


답변

되풀이. “커버 아래에”상태 머신을 생성하여 기능의 추가 사이클마다 어디에 있었는지 기억하고 거기서 선택합니다.


답변

수확량에는 크게 두 가지 용도가 있습니다.

  1. 임시 컬렉션을 만들지 않고 사용자 지정 반복을 제공하는 데 도움이됩니다.

  2. 스테이트 풀 반복을 수행하는 데 도움이됩니다.
    여기에 이미지 설명을 입력하십시오

위의 두 가지 사항을보다 명확하게 설명하기 위해 여기에서 볼 수있는 간단한 비디오를 만들었습니다.


답변

최근 Raymond Chen은 수익률 키워드에 대한 흥미로운 기사 시리즈를 운영했습니다.

명목상 반복자 패턴을 쉽게 구현하는 데 사용되지만 상태 머신으로 일반화 할 수 있습니다. Raymond를 인용 할 필요는 없습니다. 마지막 부분은 다른 용도와도 연결되어 있습니다 (그러나 Entin의 블로그의 예는 비동기 안전 코드를 작성하는 방법을 보여줍니다).


답변

언뜻보기에, 수익률 반환은 IEnumerable 반환하는 .NET 설탕 입니다.

수확량이 없으면 컬렉션의 모든 항목이 한 번에 생성됩니다.

class SomeData
{
    public SomeData() { }

    static public IEnumerable<SomeData> CreateSomeDatas()
    {
        return new List<SomeData> {
            new SomeData(),
            new SomeData(),
            new SomeData()
        };
    }
}

yield를 사용하는 동일한 코드는 항목별로 항목을 반환합니다.

class SomeData
{
    public SomeData() { }

    static public IEnumerable<SomeData> CreateSomeDatas()
    {
        yield return new SomeData();
        yield return new SomeData();
        yield return new SomeData();
    }
}

yield를 사용하면 데이터를 소비하는 함수가 컬렉션의 첫 번째 항목 만 필요로하는 경우 나머지 항목은 생성되지 않습니다.

수익률 연산자를 사용하면 필요에 따라 항목을 만들 수 있습니다. 그것을 사용해야하는 좋은 이유입니다.


답변

yield return열거 자와 함께 사용됩니다. yield of call 문에서 제어는 호출자에게 반환되지만 수신자의 상태는 유지됩니다. 이로 인해 호출자가 다음 요소를 열거 할 때 명령문 바로 다음 명령문에서 호출 수신자 메소드에서 실행을 계속 yield합니다.

이것을 예로 들어 보도록합시다. 이 예제에서 각 줄에 해당하는 실행 흐름 순서를 언급했습니다.

static void Main(string[] args)
{
    foreach (int fib in Fibs(6))//1, 5
    {
        Console.WriteLine(fib + " ");//4, 10
    }
}

static IEnumerable<int> Fibs(int fibCount)
{
    for (int i = 0, prevFib = 0, currFib = 1; i < fibCount; i++)//2
    {
        yield return prevFib;//3, 9
        int newFib = prevFib + currFib;//6
        prevFib = currFib;//7
        currFib = newFib;//8
    }
}

또한 상태는 각 열거마다 유지됩니다. Fibs()메소드를 다시 호출 하면 상태가 재설정됩니다.


답변

직관적으로 키워드는 떠나지 않고 함수에서 값을 반환합니다. 예를 들어 코드 예제에서는 현재 item값을 반환 한 다음 루프를 다시 시작합니다. 더 공식적으로, 그것은 컴파일러가 iterator에 대한 코드를 생성하는 데 사용됩니다 . 반복자는 IEnumerable객체 를 반환하는 함수입니다 . MSDN은 여러 가지가 기사 그들에 대해합니다.