No entanto, a documentação do MSDN menciona, mas não explica. Essa é uma maneira ruim de provocar um desenvolvedor faminto por conhecimento.
28412 Phil
3
O retorno do rendimento elimina a necessidade de uma lista de suporte, ou seja, você não precisa codificar algo como MyList.Add(...)apenas fazer yield return .... Se você precisa sair do loop prematuramente e retornar a lista de apoio virtual que você usaryield break;
The Muffin Man
Respostas:
529
Ele especifica que um iterador chegou ao fim. Você pode pensar yield breakem uma returndeclaração que não retorna um valor.
Por exemplo, se você definir uma função como um iterador, o corpo da função poderá ser assim:
for(int i =0; i <5; i++){yieldreturn i;}Console.Out.WriteLine("You will see me");
Observe que após o loop concluir todos os seus ciclos, a última linha é executada e você verá a mensagem no aplicativo do console.
Ou assim com yield break:
int i =0;while(true){if(i <5){yieldreturn i;}else{// note that i++ will not be executed after thisyieldbreak;}
i++;}Console.Out.WriteLine("Won't see me");
Nesse caso, a última instrução nunca é executada porque deixamos a função mais cedo.
Poderia ser simplesmente em breakvez de yield breakno seu exemplo acima? O compilador não se queixa disso.
orad 3/06/14
85
@ orad simples breakneste caso interromperia o loop, mas não abortaria a execução do método, assim a última linha seria executada e o "Won't see me text" seria realmente visto.
Damir Zekić
5
@Damir Zekić Você também pode adicionar à sua resposta por que você prefere uma quebra de rendimento sobre o retorno e quais são as diferenças entre os dois?
Bruno Costa
11
@ DamirZekić retornando nulo e quebra de rendimento não é o mesmo. Se você retornar nulo, poderá NullReferenceExceptionobter o enumerador de IEnumerable, enquanto que com a quebra de rendimento, não o fará (há uma instância sem elementos).
Bruno Costa
6
@BrunoCosta Tentar obter retornos regulares no mesmo método gera um erro do compilador. Usando yield return xalertas no compilador, você deseja que esse método seja um açúcar sintático para a criação de um Enumeratorobjeto. Este enumerador tem método MoveNext()e propriedade Current. MoveNext () executa o método até uma yield returninstrução e transforma esse valor em Current. Na próxima vez que MoveNext for chamado, a execução continuará a partir daí. yield breakdefine Current como null, sinalizando o final desse enumerador, para que umforeach (var x in myEnum()) termine.
Wolfzoon
57
Termina um bloco iterador (por exemplo, diz que não há mais elementos no IEnumerable).
com [+1] - embora academicamente não haja iteradores no .NET. somente enumeradores (uma direção, frente).
Shaun Wilson
@Shaun Wilson, mas com yieldpalavra-chave que você pode iterar coleção em ambas as direções, além disso você pode tomar cada elemento seguinte da coleção não em uma fileira
monstr
@monstr, você pode iterar a coleção de qualquer maneira e não precisa yieldfazê-lo. não estou dizendo que você está errado, entendo o que você está sugerindo; mas academicamente não há iteradores no .NET, apenas enumeradores (uma direção, encaminhamento) - diferentemente do stdc ++, não há uma "estrutura genérica de iterador" definida no CTS / CLR. O LINQ ajuda a fechar a lacuna com métodos de extensão que utilizam yield returne também métodos de retorno de chamada , mas são métodos de extensão de primeira classe, não iteradores de primeira classe. o resultado IEnumerablenão pode, por si só, repetir em outra direção que não seja o redirecionamento do chamador.
Shaun Wilson
29
Diz ao iterador que chegou ao fim.
Como um exemplo:
publicinterfaceINode{IEnumerable<Node>GetChildren();}publicclassNodeWithTenChildren:INode{privateNode[] m_children =newNode[10];publicIEnumerable<Node>GetChildren(){for(int n =0; n <10;++n ){yieldreturn m_children[ n ];}}}publicclassNodeWithNoChildren:INode{publicIEnumerable<Node>GetChildren(){yieldbreak;}}
yieldbasicamente faz com que um IEnumerable<T>método se comporte de maneira semelhante a um encadeamento agendado cooperativamente (em oposição a preventivamente).
yield returné como um thread que chama uma função "agendamento" ou "suspensão" para abrir mão do controle da CPU. Assim como um encadeamento, o IEnumerable<T>método recupera os controles no ponto imediatamente depois, com todas as variáveis locais tendo os mesmos valores que tinham antes do controle ser liberado.
yield break é como um thread que chega ao fim de sua função e termina.
As pessoas falam sobre uma "máquina de estado", mas uma máquina de estado é tudo um "fio" realmente é. Um encadeamento possui algum estado (ou seja, valores de variáveis locais) e, toda vez que é agendado, ele executa algumas ações para alcançar um novo estado. O ponto principal yieldé que, diferentemente dos threads do sistema operacional a que estamos acostumados, o código que o utiliza é congelado no tempo até que a iteração seja avançada ou finalizada manualmente.
A yield breakinstrução faz com que a enumeração pare. Com efeito, yield breakconclui a enumeração sem retornar nenhum item adicional.
Considere que, na verdade, existem duas maneiras pelas quais um método iterador pode parar de iterar. Em um caso, a lógica do método poderia naturalmente sair do método depois de retornar todos os itens. Aqui está um exemplo:
IEnumerable<uint>FindPrimes(uint startAt,uint maxCount){for(var i =0UL; i < maxCount; i++){
startAt =NextPrime(startAt);yieldreturn startAt;}Debug.WriteLine("All the primes were found.");}
No exemplo acima, o método do iterador interromperá naturalmente a execução após a localização dos maxCountprimos.
A yield breakdeclaração é outra maneira de o iterador parar de enumerar. É uma maneira de interromper a enumeração mais cedo. Aqui está o mesmo método acima. Desta vez, o método tem um limite para a quantidade de tempo que o método pode executar.
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);yieldreturn startAt;if(sw.Elapsed.TotalMinutes> maxMinutes)yieldbreak;}Debug.WriteLine("All the primes were found.");}
Observe a chamada para yield break. Com efeito, está saindo da enumeração mais cedo.
Observe também que o yield breaktrabalho funciona de maneira diferente do que apenas uma planície break. No exemplo acima, yield breaksai do método sem fazer a chamada para Debug.WriteLine(..).
público estático IEnumerable <int> Range (int min, int max)
{
enquanto (verdadeiro)
{
if (min> = max)
{
quebra de rendimento;
}
retorno de rendimento min ++;
}
}
e explicação, que se uma yield breakinstrução for atingida em um método, a execução desse método será interrompida sem retorno. Existem algumas situações em que, quando você não deseja dar nenhum resultado, pode usar a quebra de rendimento.
Bem, eles só são complicados se você se importa com o código em que são compilados. O código que os utiliza é bastante simples.
Robert Rossney 24/10/08
@ Robert, foi isso que eu quis dizer, por isso atualizei a resposta para incluir o seu comentário
Tony Lee
-2
A palavra-chave yield é usada junto com a palavra-chave return para fornecer um valor ao objeto enumerador. retorno de rendimento especifica o valor ou valores retornados. Quando a declaração de retorno de rendimento é alcançada, o local atual é armazenado. A execução é reiniciada nesse local na próxima vez que o iterador for chamado.
Os valores retornados quando iterados são: 0, 2, 5.
É importante observar que a variável de contador neste exemplo é uma variável local. Após a segunda iteração que retorna o valor 2, a terceira iteração começa de onde saiu antes, preservando o valor anterior da variável local denominada counter, que era 2.
Eu não acho que yield returnrealmente suporta o retorno de vários valores. Talvez não seja isso que você realmente quis dizer, mas é assim que eu li.
Sam
Sam - o método SampleNumbers com várias instruções de retorno de rendimento realmente funciona, o valor do iterador é retornado imediatamente e a execução é retomada quando o próximo valor for solicitado. Vi pessoas terminando um método como esse com "quebra de rendimento", mas é desnecessário. Bater a fim do método também termina a iteração
Loren Paulsen
a razão pela qual este é um exemplo ruim yield breaké que ele não contém um enumerador no nível do idioma como a foreach- ao usar um enumerador, o yield breakvalor real é fornecido. este exemplo parece um loop desenrolado. você quase nunca verá esse código no mundo real (todos nós podemos pensar em alguns casos extremos, com certeza) também, não há "iterador" aqui. o "bloco iterador" não pode se estender além do método como uma questão de especificação de linguagem. o que realmente está sendo retornado é um "enumerável", consulte também: stackoverflow.com/questions/742497/…
MyList.Add(...)
apenas fazeryield return ...
. Se você precisa sair do loop prematuramente e retornar a lista de apoio virtual que você usaryield break;
Respostas:
Ele especifica que um iterador chegou ao fim. Você pode pensar
yield break
em umareturn
declaração que não retorna um valor.Por exemplo, se você definir uma função como um iterador, o corpo da função poderá ser assim:
Observe que após o loop concluir todos os seus ciclos, a última linha é executada e você verá a mensagem no aplicativo do console.
Ou assim com
yield break
:Nesse caso, a última instrução nunca é executada porque deixamos a função mais cedo.
fonte
break
vez deyield break
no seu exemplo acima? O compilador não se queixa disso.break
neste caso interromperia o loop, mas não abortaria a execução do método, assim a última linha seria executada e o "Won't see me text" seria realmente visto.NullReferenceException
obter o enumerador de IEnumerable, enquanto que com a quebra de rendimento, não o fará (há uma instância sem elementos).yield return x
alertas no compilador, você deseja que esse método seja um açúcar sintático para a criação de umEnumerator
objeto. Este enumerador tem métodoMoveNext()
e propriedadeCurrent
. MoveNext () executa o método até umayield return
instrução e transforma esse valor emCurrent
. Na próxima vez que MoveNext for chamado, a execução continuará a partir daí.yield break
define Current como null, sinalizando o final desse enumerador, para que umforeach (var x in myEnum())
termine.Termina um bloco iterador (por exemplo, diz que não há mais elementos no IEnumerable).
fonte
yield
palavra-chave que você pode iterar coleção em ambas as direções, além disso você pode tomar cada elemento seguinte da coleção não em uma fileirayield
fazê-lo. não estou dizendo que você está errado, entendo o que você está sugerindo; mas academicamente não há iteradores no .NET, apenas enumeradores (uma direção, encaminhamento) - diferentemente do stdc ++, não há uma "estrutura genérica de iterador" definida no CTS / CLR. O LINQ ajuda a fechar a lacuna com métodos de extensão que utilizamyield return
e também métodos de retorno de chamada , mas são métodos de extensão de primeira classe, não iteradores de primeira classe. o resultadoIEnumerable
não pode, por si só, repetir em outra direção que não seja o redirecionamento do chamador.Diz ao iterador que chegou ao fim.
Como um exemplo:
fonte
yield
basicamente faz com que umIEnumerable<T>
método se comporte de maneira semelhante a um encadeamento agendado cooperativamente (em oposição a preventivamente).yield return
é como um thread que chama uma função "agendamento" ou "suspensão" para abrir mão do controle da CPU. Assim como um encadeamento, oIEnumerable<T>
método recupera os controles no ponto imediatamente depois, com todas as variáveis locais tendo os mesmos valores que tinham antes do controle ser liberado.yield break
é como um thread que chega ao fim de sua função e termina.As pessoas falam sobre uma "máquina de estado", mas uma máquina de estado é tudo um "fio" realmente é. Um encadeamento possui algum estado (ou seja, valores de variáveis locais) e, toda vez que é agendado, ele executa algumas ações para alcançar um novo estado. O ponto principal
yield
é que, diferentemente dos threads do sistema operacional a que estamos acostumados, o código que o utiliza é congelado no tempo até que a iteração seja avançada ou finalizada manualmente.fonte
Todo o assunto dos blocos iteradores é abordado bem neste capítulo de amostra grátis do livro C # in Depth de Jon Skeet .
fonte
A
yield break
instrução faz com que a enumeração pare. Com efeito,yield break
conclui a enumeração sem retornar nenhum item adicional.Considere que, na verdade, existem duas maneiras pelas quais um método iterador pode parar de iterar. Em um caso, a lógica do método poderia naturalmente sair do método depois de retornar todos os itens. Aqui está um exemplo:
No exemplo acima, o método do iterador interromperá naturalmente a execução após a localização dos
maxCount
primos.A
yield break
declaração é outra maneira de o iterador parar de enumerar. É uma maneira de interromper a enumeração mais cedo. Aqui está o mesmo método acima. Desta vez, o método tem um limite para a quantidade de tempo que o método pode executar.Observe a chamada para
yield break
. Com efeito, está saindo da enumeração mais cedo.Observe também que o
yield break
trabalho funciona de maneira diferente do que apenas uma planíciebreak
. No exemplo acima,yield break
sai do método sem fazer a chamada paraDebug.WriteLine(..)
.fonte
Aqui http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/ é um exemplo muito bom:
e explicação, que se uma
yield break
instrução for atingida em um método, a execução desse método será interrompida sem retorno. Existem algumas situações em que, quando você não deseja dar nenhum resultado, pode usar a quebra de rendimento.fonte
quebra de rendimento é apenas uma maneira de dizer retorno pela última vez e não retornar nenhum valor
por exemplo
fonte
Se o que você quer dizer com "o que realmente produz quebra", é "como funciona" - consulte o blog de Raymond Chen para obter detalhes https://devblogs.microsoft.com/oldnewthing/20080812-00/?p=21273
Os iteradores C # geram código muito complicado.
fonte
A palavra-chave yield é usada junto com a palavra-chave return para fornecer um valor ao objeto enumerador. retorno de rendimento especifica o valor ou valores retornados. Quando a declaração de retorno de rendimento é alcançada, o local atual é armazenado. A execução é reiniciada nesse local na próxima vez que o iterador for chamado.
Para explicar o significado usando um exemplo:
Os valores retornados quando iterados são: 0, 2, 5.
É importante observar que a variável de contador neste exemplo é uma variável local. Após a segunda iteração que retorna o valor 2, a terceira iteração começa de onde saiu antes, preservando o valor anterior da variável local denominada counter, que era 2.
fonte
yield break
fazyield return
realmente suporta o retorno de vários valores. Talvez não seja isso que você realmente quis dizer, mas é assim que eu li.yield break
é que ele não contém um enumerador no nível do idioma como aforeach
- ao usar um enumerador, oyield break
valor real é fornecido. este exemplo parece um loop desenrolado. você quase nunca verá esse código no mundo real (todos nós podemos pensar em alguns casos extremos, com certeza) também, não há "iterador" aqui. o "bloco iterador" não pode se estender além do método como uma questão de especificação de linguagem. o que realmente está sendo retornado é um "enumerável", consulte também: stackoverflow.com/questions/742497/…