“수율은 무엇입니까?” C #에서합니까?


494

MSDN에서이 구문을 yield break보았지만 그 기능을 모르겠습니다. 아는 사람 있나요?


26
그러나 MSDN 설명서에 언급되어 있지만 설명하지는 않습니다. 지식이 부족한 개발자를 괴롭히는 나쁜 방법입니다.
Phil

3
수익률 반환은 지원 목록이 필요하지 않습니다. 즉, MyList.Add(...)그냥 do 와 같은 코드를 작성할 필요가 없습니다 yield return .... 루프를 조기에 중단하고 사용하는 가상 지원 목록을 반환해야하는 경우yield break;
Muffin Man

답변:


529

반복자가 끝났음을 지정합니다. 값을 리턴하지 않는 명령문 yield break으로 생각할 수 있습니다 return.

예를 들어, 함수를 반복자로 정의하면 함수 본문은 다음과 같습니다.

for (int i = 0; i < 5; i++)
{
    yield return i;
}

Console.Out.WriteLine("You will see me");

루프가 모든 사이클을 완료하면 마지막 줄이 실행되고 콘솔 앱에 메시지가 표시됩니다.

또는 다음과 같이 yield break:

int i = 0;
while (true)
{
    if (i < 5)
    {
        yield return i;
    }
    else
    {
        // note that i++ will not be executed after this
        yield break;
    }
    i++;
}

Console.Out.WriteLine("Won't see me");

이 경우 마지막 명령문은 함수를 일찍 종료했기 때문에 실행되지 않습니다.


8
위의 예 break대신 간단 하지 않을 수 yield break있습니까? 컴파일러는 그것에 대해 불평하지 않습니다.
orad

85
break이 경우 간단한 @orad는 루프를 중지하지만 메소드 실행을 중단하지 않으므로 마지막 행이 실행되고 "Wo n't see text"가 실제로 표시됩니다.
Damir Zekić 2016 년

5
@Damir Zekić 당신은 또한 당신이 왜 수익률보다 수익률을 선호해야하는지, 그리고 둘과의 차이점은 무엇입니까?
Bruno Costa

11
@ DamirZekić가 null을 반환하고 수익률 중단 동일 하지 않습니다 . null을 반환 NullReferenceException하면 IEnumerable의 열거자를 가져올 수 있지만 yield break는하지 않습니다 (요소가없는 인스턴스가 있음).
Bruno Costa

6
@BrunoCosta 동일한 메소드에서 정기적으로 리턴하려고하면 컴파일러 오류가 발생합니다. yield return x경고를 사용 하면 컴파일러에서이 메소드가 Enumerator객체 를 작성하기위한 구문 설탕이되기를 원합니다 . 이 열거 자에는 method MoveNext()와 property가 Current있습니다. MoveNext ()는 yield return명령문 까지 메소드를 실행하고 해당 값을로 바꿉니다 Current. 다음에 MoveNext를 호출하면 거기서부터 실행이 계속됩니다. yield breakCurrent를 null로 설정하여이 열거 자의 끝을 알리므로 a foreach (var x in myEnum())가 끝납니다.
Wolfzoon

57

반복자 블록을 종료합니다 (예 : IEnumerable에 더 이상 요소가 없다고 말함).


2
학술적으로 .NET에는 반복자가 없지만 [+1] 사용. 열거 자만 (한 방향, 앞으로)
Shaun Wilson

와 @Shaun 윌슨은, 그러나 yield당신이 양쪽 방향으로 집합을 반복 할 수있는 키워드, 또한 당신이 아닌 행의 콜렉션의 모든 다음 요소를 취할 수
monstr

@monstr 어떤 방식 으로든 컬렉션을 반복 할 수 있으며 따로 할 필요가 없습니다 yield. 나는 당신이 틀렸다고 말하는 것이 아니라, 당신이 제안하는 것을 봅니다. 그러나 학문적으로 .NET에는 반복자가 없으며 열거 자 (한 방향, 앞으로) 만 있습니다. stdc ++와 달리 CTS / CLR에 정의 된 "일반 반복자 프레임 워크"는 없습니다. LINQ yield return 는 콜백 메소드를 활용하는 확장 메소드와의 격차를 좁히는 데 도움이 되지만 일류 반복자가 아닌 일류 확장 메소드입니다. 결과 IEnumerable는 발신자에게 전달하는 것 이외의 다른 방향으로 반복 될 수 없습니다.
Shaun Wilson

29

반복자에게 끝까지 도달했음을 알려줍니다.

예로서:

public interface INode
{
    IEnumerable<Node> GetChildren();
}

public class NodeWithTenChildren : INode
{
    private Node[] m_children = new Node[10];

    public IEnumerable<Node> GetChildren()
    {
        for( int n = 0; n < 10; ++n )
        {
            yield return m_children[ n ];
        }
    }
}

public class NodeWithNoChildren : INode
{
    public IEnumerable<Node> GetChildren()
    {
        yield break;
    }
}

21

yield기본적으로 IEnumerable<T>메소드는 협력 적으로 (선점 적으로 반대로) 예약 된 스레드와 유사하게 작동합니다.

yield return"schedule"또는 "sleep"함수를 호출하여 CPU 제어를 포기하는 스레드와 같습니다. 스레드와 IEnumerable<T>마찬가지로이 메소드는 제어가 포기되기 전의 값과 동일한 값을 갖는 모든 로컬 변수를 사용하여 즉시 제어를 다시 얻습니다.

yield break 스레드가 기능의 끝에 도달하고 종료되는 것과 같습니다.

사람들은 "상태 머신"에 대해 이야기하지만 상태 머신은 모두 "스레드"입니다. 스레드에는 상태 (예 : 로컬 변수 값)가 있으며, 예약 될 때마다 새 상태에 도달하기 위해 몇 가지 조치를 수행합니다. 중요한 점은 yield우리가 익숙한 운영 체제 스레드와 달리이 코드를 사용하는 코드는 반복이 수동으로 진행되거나 종료 될 때까지 시간에 고정된다는 것입니다.



9

yield break문 정지에 열거됩니다. 실제로 yield break추가 항목을 반환하지 않고 열거를 완료합니다.

실제로 반복자 메소드가 반복을 중지 할 수있는 두 가지 방법이 있습니다. 어떤 경우에는 메소드의 로직이 모든 항목을 반환 한 후 메소드를 자연스럽게 종료 할 수 있습니다. 예를 들면 다음과 같습니다.

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount)
{
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;
    }

    Debug.WriteLine("All the primes were found.");
}

위 예제에서 maxCount프라임이 발견 되면 반복자 메소드는 자연스럽게 실행을 중지 합니다.

yield break문은 반복자가 열거를 중단하는 또 다른 방법입니다. 열거 형을 일찍 벗어나는 방법입니다. 위와 같은 방법이 있습니다. 이번에는 메소드가 실행할 수있는 시간에 제한이 있습니다.

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount, int maxMinutes)
{
    var sw = System.Diagnostics.Stopwatch.StartNew();
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;

        if (sw.Elapsed.TotalMinutes > maxMinutes)
            yield break;
    }

    Debug.WriteLine("All the primes were found.");
}

에 대한 호출을 확인하십시오 yield break. 실제로 열거 형이 일찍 종료됩니다.

또한 yield break작품은 평범한 것과 다르게 작동합니다 break. 위의 예 yield break에서를 호출하지 않고 메소드를 종료합니다 Debug.WriteLine(..).


7

여기에 http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/ 가 아주 좋은 예입니다.

공용 정적 IEnumerable <int> 범위 (int min, int max)
{
   동안 (true)
   {
      if (min> = max)
      {
         항복 중단;
      }
      수율 반환 min ++;
   }
}

설명 yield break은 메소드 내 에서 명령문이 적중 되면 해당 메소드의 실행이 리턴없이 중지된다고 설명합니다. 결과를 제공하지 않으려는 경우가 있습니다. 항복 중단을 사용할 수 있습니다.


5

수익률 중단은 마지막으로 수익을 말하는 방법이며 어떤 값도 반환하지 않습니다

예 :

// returns 1,2,3,4,5
IEnumerable<int> CountToFive()
{
    yield return 1;
    yield return 2;
    yield return 3;
    yield return 4;
    yield return 5;
    yield break;
    yield return 6;
    yield return 7;
    yield return 8;
    yield return 9;
 }

4

"수율이 실제로 무엇을 하는가"가 의미하는 바는 "어떻게 작동 하는가"입니다. 자세한 내용은 Raymond Chen의 블로그를 참조하십시오. https://devblogs.microsoft.com/oldnewthing/20080812-00/?p=21273

C # 반복자는 매우 복잡한 코드를 생성합니다.


12
글쎄, 그것들은 그들이 컴파일 된 코드에 관심이 있다면 복잡합니다. 그것들을 사용하는 코드는 매우 간단합니다.
Robert Rossney

@Robert, 이것이 제가 의미 한 바입니다. 귀하의 의견을 포함하여 답변을 업데이트했습니다
Tony Lee

-2

yield 키워드는 return 키워드와 함께 사용되어 열거 자 객체에 값을 제공합니다. yield return반환 되는 값을 지정합니다. yield return statement에 도달하면 현재 위치가 저장됩니다. 다음에 이터레이터가 호출 될 때이 위치에서 실행이 다시 시작됩니다.

예를 사용하여 의미를 설명하려면 :

    public IEnumerable<int> SampleNumbers()
    {
        int counter = 0;
        yield return counter;

        counter = counter + 2;

        yield return counter;

        counter = counter + 3;

        yield return counter ;
    }

이것이 반복 될 때 리턴되는 값은 0, 2, 5입니다.

이 예제에서 카운터 변수는 로컬 변수라는 점에 유의해야 합니다. 값 2를 리턴하는 두 번째 반복 후에 세 번째 반복은 이전에 있던 위치에서 시작하며 counter 라는 로컬 변수의 이전 값 은 2입니다.


11
당신은 무엇인지 설명하지 yield break않습니다
제이 설리반에게

yield return실제로 여러 값 반환을 지원 하지 않는다고 생각 합니다. 어쩌면 그것은 당신이 실제로 의미하는 것이 아니지만, 내가 그것을 읽는 방법입니다.
Sam

Sam-여러 수익률 반환 문이있는 SampleNumbers 메서드가 실제로 작동하고 반복기 값이 즉시 반환되고 다음 값이 요청되면 실행이 재개됩니다. 나는 사람들이 "수율 나누기"를 사용하여 이와 같은 방법을 끝내는 것을 보았지만 불필요하다. 메소드의 끝을 때리는 것 또한 반복자를 종료합니다
Loren Paulsen

이것이 나쁜 예인 이유 는 열거자를 사용할 때 실제 가치를 제공 하는 yield break것과 같은 언어 수준 열거자를 포함하지 않기 때문 입니다. 이 예제는 언롤 된 루프처럼 보입니다. 실제 코드에서는이 코드를 거의 보지 못할 것입니다 (우리는 모두 엣지 케이스를 생각할 수 있습니다). 여기에는 "반복자"가 없습니다. "반복자 블록"은 언어 사양에 따라 메소드를 넘어 확장 할 수 없습니다. 실제로 반환되는 것은 "열거 가능"입니다. stackoverflow.com/questions/742497/…foreachyield break
Shaun Wilson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.