Após quase 4 anos de experiência, não vi um código em que a palavra-chave yield seja usada. Alguém pode me mostrar um uso prático (juntamente com a explicação) dessa palavra-chave e, se sim, não existem outras maneiras mais fáceis de cumprir o que ela pode fazer?
76
yield
pode ser usado em geral.Respostas:
Eficiência
A
yield
palavra-chave cria efetivamente uma enumeração lenta sobre itens de coleção que podem ser muito mais eficientes. Por exemplo, se oforeach
loop iterar apenas os 5 primeiros itens de 1 milhão de itens, tudo seráyield
retornado e você não acumulou uma coleção de 1 milhão de itens internamente primeiro. Da mesma forma, você desejará usaryield
comIEnumerable<T>
valores de retorno em seus próprios cenários de programação para obter as mesmas eficiências.Exemplo de eficiência obtida em um determinado cenário
Não é um método iterador, uso potencialmente ineficiente de uma grande coleção
(a coleção intermediária é criada com muitos itens)
Versão do iterador, eficiente
(nenhuma coleção intermediária é criada)
Simplifique alguns cenários de programação
Em outro caso, facilita a programação de alguns tipos de classificação e mesclagem de listas, porque você apenas
yield
retorna os itens na ordem desejada, em vez de ordená-los em uma coleção intermediária e trocá-los por lá. Existem muitos cenários desse tipo.Apenas um exemplo é a mesclagem de duas listas:
Esse método retorna uma lista contígua de itens, efetivamente uma mesclagem sem nenhuma coleção intermediária necessária.
Mais informações
A
yield
chave só pode ser utilizado em contexto de um método iteração (tendo um tipo de retornoIEnumerable
,IEnumerator
,IEnumerable<T>
, ouIEnumerator<T>
.) E existe uma relação especial comforeach
. Iteradores são métodos especiais. A documentação de produção e o iterador do MSDN contêm muitas informações e explicações interessantes dos conceitos. Certifique-se de correlacioná-lo com aforeach
palavra - chave lendo sobre isso também, para complementar sua compreensão dos iteradores.Para aprender sobre como os iteradores alcançam sua eficiência, o segredo está no código IL gerado pelo compilador C #. A IL gerada para um método iterador difere drasticamente da gerada para um método regular (não iterador). Este artigo (O que a palavra-chave Rendimento realmente gera?) Fornece esse tipo de insight.
fonte
database.Customers.Count()
enumera toda a enumeração de clientes, exigindo, assim, que o código mais eficiente passe por cada item?Há algum tempo, tive um exemplo prático, vamos supor que você tenha uma situação como esta:
O objeto botão não conhece sua própria posição na coleção. A mesma limitação se aplica a
Dictionary<T>
ou outros tipos de coleções.Aqui está minha solução usando a
yield
palavra-chave:E é assim que eu uso:
Não preciso fazer um
for
loop na minha coleção para encontrar o índice. O My Button tem um ID e isso também é usado como índiceIndexerList<T>
, para evitar IDs ou índices redundantes - é disso que eu gosto! O índice / ID pode ser um número arbitrário.fonte
Um exemplo prático pode ser encontrado aqui:
http://www.ytechie.com/2009/02/using-c-yield-for-readability-and-performance.html
Há várias vantagens em usar o rendimento sobre o código padrão:
No entanto, como Jan_V disse (apenas me derrote por alguns segundos :-) você pode viver sem ele, porque internamente o compilador produzirá código quase idêntico nos dois casos.
fonte
Aqui está um exemplo:
https://bitbucket.org/ant512/workingweek/src/a745d02ba16f/source/WorkingWeek/Week.cs#cl-158
A turma realiza cálculos de datas com base em uma semana útil. Posso dizer a um exemplo da classe que Bob trabalha das 9:30 às 17:30 todos os dias da semana, com uma hora de intervalo para o almoço às 12:30. Com esse conhecimento, a função AscendingShifts () produzirá objetos de turno de trabalho entre as datas fornecidas. Para listar todos os turnos de trabalho de Bob entre 1º de janeiro e 1º de fevereiro deste ano, use-o assim:
A classe realmente não interage com uma coleção. No entanto, as mudanças entre duas datas podem ser consideradas como uma coleção. O
yield
operador torna possível iterar sobre essa coleção imaginada sem criar a própria coleção.fonte
Eu tenho uma pequena camada de dados db que possui uma
command
classe na qual você define o texto do comando SQL, o tipo de comando e retorna um IEnumerable de 'parâmetros de comando'.Basicamente, a idéia é digitar comandos CLR em vez de preencher manualmente
SqlCommand
propriedades e parâmetros o tempo todo.Portanto, há uma função que se parece com isso:
A classe que herda essa
command
classe tem as propriedadesAge
eName
.Em seguida, você pode criar um novo
command
objeto que preencha suas propriedades e passá-lo para umadb
interface que realmente faz a chamada de comando.Em suma, é realmente fácil trabalhar com comandos SQL e mantê-los digitados.
fonte
Embora o caso de fusão já tenha sido coberto na resposta aceita, deixe-me mostrar o método de extensão de parâmetros de produção e mesclagem ™:
Eu uso isso para construir pacotes de um protocolo de rede:
O
MarkChecksum
método, por exemplo, se parece com isso. E temyield
também:Mas tenha cuidado ao usar métodos agregados como Sum () em um método de enumeração, pois eles acionam um processo de enumeração separado.
fonte
O repositório de exemplos do Elastic Search .NET tem um ótimo exemplo de
yield return
como particionar uma coleção em várias coleções com um tamanho especificado:https://github.com/elastic/elasticsearch-net-example/blob/master/src/NuSearch.Domain/Extensions/PartitionExtension.cs
fonte
Expandindo a resposta de Jan_V, acabei de encontrar um caso do mundo real relacionado a ele:
Eu precisava usar as versões Kernel32 do FindFirstFile / FindNextFile. Você identifica a primeira chamada e a alimenta em todas as chamadas subseqüentes. Coloque isso em um enumerador e você obterá algo que você pode usar diretamente com o foreach.
fonte