Domanda

io so cosa yield fa, e ho visto alcuni esempi, ma non riesco a pensare ad applicazioni nella vita reale, lo hai usato per risolvere qualche problema specifico?

(Idealmente qualche problema che non può essere risolto in altro modo)

È stato utile?

Soluzione

Mi rendo conto che questa è una vecchia domanda (pre-Jon Skeet?), ma ho preso in considerazione questa domanda anch'io ultimamente.Sfortunatamente le risposte attuali qui (secondo me) non menzionano il vantaggio più ovvio della dichiarazione di rendimento.

Il vantaggio più grande dell'istruzione yield è che consente di scorrere elenchi molto grandi con un utilizzo della memoria molto più efficiente rispetto all'utilizzo, ad esempio, di un elenco standard.

Ad esempio, supponiamo che tu abbia una query sul database che restituisce 1 milione di righe.È possibile recuperare tutte le righe utilizzando un DataReader e memorizzarle in un elenco, richiedendo quindi list_size * row_size byte di memoria.

Oppure potresti utilizzare l'istruzione yield per creare un Iterator e archiviare in memoria solo una riga alla volta.In effetti questo ti dà la possibilità di fornire una funzionalità di "streaming" su grandi insiemi di dati.

Inoltre, nel codice che utilizza Iterator, si utilizza un semplice ciclo foreach e si può decidere di uscire dal ciclo come richiesto.Se interrompi presto, non hai forzato il recupero dell'intero set di dati quando ti servivano solo le prime 5 righe (ad esempio).

Per quanto riguarda:

Ideally some problem that cannot be solved some other way

L'istruzione yield non ti fornisce nulla che non potresti fare utilizzando la tua implementazione personalizzata dell'iteratore, ma ti evita di dover scrivere il codice spesso complesso necessario.Ci sono pochissimi problemi (se ce ne sono) che non possono essere risolti in più di un modo.

Ecco un paio di domande e risposte più recenti che forniscono maggiori dettagli:

Rendimento del valore aggiunto delle parole chiave?

Yield è utile al di fuori di LINQ?

Altri suggerimenti

attualmente lo utilizzo in modo non tradizionale sul mio sito 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;
}

quindi in pratica controlla se la visualizzazione dell'idea è attualmente autorizzata e, in tal caso, restituisce l'idea.Se non lo è, viene semplicemente saltato.Ciò mi consente di memorizzare nella cache le idee ma di visualizzarle comunque agli utenti autorizzati.Altrimenti dovrei recuperarli ogni volta in base alle autorizzazioni, quando vengono riclassificati solo ogni 1 ora.

Un uso interessante è come meccanismo per la programmazione asincrona, specialmente per attività che richiedono più passaggi e richiedono lo stesso set di dati in ogni passaggio.Due esempi di questo potrebbero essere Jeffery Richters AysncEnumerator Parte 1 E Parte 2.Anche il Concurrency and Coordination Runtime (CCR) utilizza questa tecnica Iteratori CCR.

Gli operatori LINQ sulla classe Enumerable vengono implementati come iteratori creati con l'istruzione yield.Ti consente di concatenare operazioni come Select() e Where() senza enumerare effettivamente nulla finché non utilizzi effettivamente l'enumeratore in un ciclo, in genere utilizzando il comando per ciascuno dichiarazione.Inoltre, poiché viene calcolato un solo valore quando chiami IEnumerator.MoveNext() se decidi di interrompere la raccolta a metà, risparmierai il calo di prestazioni derivante dal calcolo di tutti i risultati.

Gli iteratori possono essere utilizzati anche per implementare altri tipi di valutazione pigra in cui le espressioni vengono valutate solo quando necessario.Puoi anche usare prodotto per cose più fantasiose come le coroutine.

Un altro buon utilizzo di yield è eseguire una funzione sugli elementi di un IEnumerable e restituire un risultato di tipo diverso, ad esempio:

public delegate T SomeDelegate(K obj);

public IEnumerable<T> DoActionOnList(IEnumerable<K> list, SomeDelegate action)
{
    foreach (var i in list)
        yield return action(i);
}

L'utilizzo di yield può impedire il downcasting a un tipo concreto.Questo è utile per garantire che il consumatore della raccolta non la manipoli.

Puoi anche usare yield return per trattare una serie di risultati di funzioni come un elenco.Consideriamo ad esempio un’azienda che paga i propri dipendenti ogni due settimane.È possibile recuperare un sottoinsieme di date delle buste paga come elenco utilizzando questo codice:

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);
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top