Efficienza
La yield
parola chiave crea effettivamente un elenco pigro sugli elementi della raccolta che può essere molto più efficiente. Ad esempio, se il tuo foreach
ciclo scorre solo sui primi 5 articoli di 1 milione di articoli, allora sono tutti yield
ritorni e non hai creato prima una raccolta di 1 milione di articoli internamente. Allo stesso modo si vuole utilizzare yield
con i IEnumerable<T>
valori di ritorno nei propri scenari di programmazione per ottenere gli stessi rendimenti.
Esempio di efficienza acquisita in un determinato scenario
Non un metodo iteratore, potenziale uso inefficiente di una grande raccolta
(la raccolta intermedia è costruita con molti elementi)
// Method returns all million items before anything can loop over them.
List<object> GetAllItems() {
List<object> millionCustomers;
database.LoadMillionCustomerRecords(millionCustomers);
return millionCustomers;
}
// MAIN example ---------------------
// Caller code sample:
int num = 0;
foreach(var itm in GetAllItems()) {
num++;
if (num == 5)
break;
}
// Note: One million items returned, but only 5 used.
Versione Iterator, efficiente
(non è stata creata alcuna raccolta intermedia)
// Yields items one at a time as the caller's foreach loop requests them
IEnumerable<object> IterateOverItems() {
for (int i; i < database.Customers.Count(); ++i)
yield return database.Customers[i];
}
// MAIN example ---------------------
// Caller code sample:
int num = 0;
foreach(var itm in IterateOverItems()) {
num++;
if (num == 5)
break;
}
// Note: Only 5 items were yielded and used out of the million.
Semplifica alcuni scenari di programmazione
In un altro caso, semplifica la programmazione di alcuni tipi di ordinamento e fusione di elenchi perché ti basta yield
riportare gli elementi nell'ordine desiderato anziché ordinarli in una raccolta intermedia e scambiarli lì. Esistono molti scenari simili.
Solo un esempio è l'unione di due elenchi:
IEnumerable<object> EfficientMerge(List<object> list1, List<object> list2) {
foreach(var o in list1)
yield return o;
foreach(var o in list2)
yield return o;
}
Questo metodo restituisce un elenco contiguo di elementi, in effetti un'unione senza la raccolta intermedia necessaria.
Ulteriori informazioni
La yield
parola chiave può essere utilizzato solo in contesto di un metodo iterator (avente un tipo di ritorno IEnumerable
, IEnumerator
, IEnumerable<T>
, o IEnumerator<T>
.) E v'è un rapporto speciale con foreach
. Gli iteratori sono metodi speciali. La documentazione sulla resa MSDN e la documentazione dell'iteratore contengono molte informazioni e spiegazioni interessanti sui concetti. Assicurati di correlarlo con la foreach
parola chiave leggendo anche su di esso, per integrare la tua comprensione degli iteratori.
Per sapere come gli iteratori raggiungono la loro efficienza, il segreto è nel codice IL generato dal compilatore C #. L'IL generato per un metodo iteratore differisce drasticamente da quello generato per un metodo normale (non iteratore). Questo articolo (Cosa genera realmente la parola chiave di rendimento?) Fornisce questo tipo di approfondimento.