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)

Foi útil?

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:

Valor agregado da palavra-chave de rendimento?

O rendimento é útil fora do LINQ?

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);
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top