Quais são as aplicações de rendimento na vida real?
Pergunta
eu sei o que yield
faz, e já vi alguns exemplos, mas não consigo pensar em aplicações da vida real, você usou para resolver algum problema específico?
(Idealmente, algum problema que não pode ser resolvido de outra maneira)
Solução
Sei que esta é uma questão antiga (antes de Jon Skeet?), Mas tenho pensado nessa questão ultimamente.Infelizmente, as respostas atuais aqui (na minha opinião) não mencionam a vantagem mais óbvia da declaração de rendimento.
O maior benefício da instrução yield é que ela permite iterar em listas muito grandes com um uso de memória muito mais eficiente do que usar, digamos, uma lista padrão.
Por exemplo, digamos que você tenha uma consulta ao banco de dados que retorne 1 milhão de linhas.Você pode recuperar todas as linhas usando um DataReader e armazená-las em uma lista, exigindo, portanto, list_size * row_size bytes de memória.
Ou você pode usar a instrução yield para criar um Iterator e armazenar apenas uma linha na memória por vez.Na verdade, isso lhe dá a capacidade de fornecer um recurso de "streaming" em grandes conjuntos de dados.
Além disso, no código que usa o Iterador, você usa um loop foreach simples e pode decidir sair do loop conforme necessário.Se você interromper antecipadamente, não forçou a recuperação de todo o conjunto de dados quando precisava apenas das primeiras 5 linhas (por exemplo).
A respeito de:
Ideally some problem that cannot be solved some other way
A instrução yield não fornece nada que você não possa fazer usando sua própria implementação de iterador customizado, mas evita a necessidade de escrever o código muitas vezes complexo necessário.Existem muito poucos problemas (se houver) que não podem ser resolvidos de mais de uma maneira.
Aqui estão algumas perguntas e respostas mais recentes que fornecem mais detalhes:
Outras dicas
na verdade, eu uso isso de uma forma não tradicional em meu site IdeaPipe
public override IEnumerator<T> GetEnumerator()
{
// goes through the collection and only returns the ones that are visible for the current user
// this is done at this level instead of the display level so that ideas do not bleed through
// on services
foreach (T idea in InternalCollection)
if (idea.IsViewingAuthorized)
yield return idea;
}
então basicamente ele verifica se a visualização da ideia está autorizada no momento e se estiver, ele retorna a ideia.Se não estiver, é simplesmente ignorado.Isso me permite armazenar em cache as ideias, mas ainda exibi-las aos usuários autorizados.Caso contrário, eu teria que retirá-los todas as vezes com base nas permissões, quando eles são reclassificados apenas a cada 1 hora.
Um uso interessante é como mecanismo de programação assíncrona, especialmente para tarefas que executam várias etapas e exigem o mesmo conjunto de dados em cada etapa.Dois exemplos disso seriam Jeffery Richters AysncEnumerator Parte 1 e Parte 2.O Tempo de Execução de Simultaneidade e Coordenação (CCR) também faz uso desta técnica Iteradores CCR.
Os operadores do LINQ na classe Enumerable são implementados como iteradores criados com a instrução yield.Ele permite encadear operações como Select() e Where() sem realmente enumerar nada até que você realmente use o enumerador em um loop, normalmente usando o método para cada declaração.Além disso, como apenas um valor é calculado quando você chama IEnumerator.MoveNext() se decidir parar no meio da coleta, você economizará o impacto no desempenho do cálculo de todos os resultados.
Os iteradores também podem ser usados para implementar outros tipos de avaliação lenta, onde as expressões são avaliadas apenas quando você precisa delas.Você também pode usar colheita para coisas mais sofisticadas, como corrotinas.
Outro bom uso do rendimento é executar uma função nos elementos de um IEnumerable e retornar um resultado de um tipo diferente, por exemplo:
public delegate T SomeDelegate(K obj);
public IEnumerable<T> DoActionOnList(IEnumerable<K> list, SomeDelegate action)
{
foreach (var i in list)
yield return action(i);
}
Usar o rendimento pode evitar a redução para um tipo de concreto.Isto é útil para garantir que o consumidor da coleção não a manipule.
Você também pode usar yield return
para tratar uma série de resultados de função como uma lista.Por exemplo, considere uma empresa que paga seus funcionários a cada duas semanas.Poderíamos recuperar um subconjunto de datas da folha de pagamento como uma lista usando este código:
void Main()
{
var StartDate = DateTime.Parse("01/01/2013");
var EndDate = DateTime.Parse("06/30/2013");
foreach (var d in GetPayrollDates(StartDate, EndDate)) {
Console.WriteLine(d);
}
}
// Calculate payroll dates in the given range.
// Assumes the first date given is a payroll date.
IEnumerable<DateTime> GetPayrollDates(DateTime startDate, DateTime endDate, int daysInPeriod = 14) {
var thisDate = startDate;
while (thisDate < endDate) {
yield return thisDate;
thisDate = thisDate.AddDays(daysInPeriod);
}
}