Come Fare gli Enumeratori e Enumerables Lavoro in C#?

0
345

C#’s IEnumerable e interfacce IEnumerator sono utilizzati da collezioni come Array e Liste di standardizzare i metodi di iterare su di loro e l’esecuzione di azioni, di filtraggio e selezione con dichiarazioni di LINQ. Parleremo di come funzionano e come usarli.

Che cosa È un Enumerabile?

Il termine “Enumerabile” definisce un oggetto che è destinato ad essere ripetuto più, passando sopra ad ogni elemento una volta in ordine. In C#, un Enumerabile è un oggetto come un array, lista, o qualsiasi altro tipo di raccolta che implementa l’interfaccia IEnumerable. Enumerables standardizzare l’esecuzione di loop su collezioni, e consente l’utilizzo di query LINQ sintassi, nonché altre utili metodi di estensione come Elenco.Dove() o un Elenco.Selezionare().

Tutta l’interfaccia IEnumerable richiede è un metodo GetEnumerator(), che restituisce un IEnumerator. Così che cosa Enumeratori fare?

Beh, IEnumerator due metodi, il metodo MoveNext() e della Corrente(). MoveNext è il metodo utilizzato per il passaggio su ogni elemento, di applicare qualsiasi tipo di custom iteratore logica nel processo, e la Corrente è un metodo utilizzato per ottenere l’elemento corrente dopo MoveNext è fatto. Si finisce con un’interfaccia che definisce gli oggetti che possono essere enumerati, e come gestire l’enumerazione.

Per esempio, ogni volta che si scrive un ciclo foreach, stai usando gli enumeratori. In realtà non puoi usare foreach su una collezione che non implementa l’interfaccia IEnumerable. Quando viene compilato, un ciclo foreach come questo:

foreach (Int elemento in elenco)
{
// il codice
}

Viene trasformato in un ciclo while, che elabora fino a quando il Enumerabile è fuori di elementi, chiamando il metodo MoveNext ogni tempo e di impostare la variabile di iterazione per .Corrente.

IEnumerator enumeratore= lista.GetEnumerator();
while (list.MoveNext())
{
elemento = (Int)enumeratore.Corrente
// il codice
}

La maggior parte del tempo, si desidera avere per implementare manualmente qualsiasi di questo, dal momento che Enumerables come le Liste sono progettati per essere utilizzati in loop e con metodi LINQ. Ma, se si desidera creare la propria collezione di classe, si potrebbe fare in modo da implementare IEnumerable e restituendo l’enumeratore della Lista memorizzare i dati.

Per le classi che hanno i campi che desideri scorrere, questo può essere un modo semplice per ripulire il codice. Invece di avere i dati di matrice pubblica e iterare CustomCollection.dataArray, si può semplicemente scorrere CustomCollection stesso. Naturalmente, se si desidera comportarsi più come una vera e propria lista, è necessario implementare altre interfacce come ICollection così.

Le Query LINQ Utilizzo di Esecuzione Differita

La cosa più importante da notare su LINQ, è che le query non sempre eseguire subito. Molti metodi di ritorno Enumerables e utilizzare differita l’esecuzione. Invece di loop a destra quando la query è fatto, in realtà attende fino a quando il Enumerabile è utilizzata nel ciclo, e quindi viene eseguita la query durante MoveNext.

Facciamo un esempio. Questa funzione prende una lista di stringhe e di stampe di ogni elemento che è più di una certa lunghezza. Usa Dove() per filtrare l’elenco, e quindi foreach per la stampa di ogni elemento.

Questa sintassi è un po ‘ di confusione, soprattutto se avete l’abitudine di usare var (che si dovrebbe sicuramente fare qui), dal momento che si può guardare come si sta generando una nuova Lista con Cui() e poi scorrere l’elenco. Nel caso di un ciclo foreach, un oggetto IEnumerable può prendere il posto di un Elenco, ma non è un Elenco—non è possibile aggiungere o rimuovere elementi.

C# è intelligente, però, e invece di scorrere la lista due volte (che sarebbe il doppio del tempo di esecuzione per nessun motivo, e di allocare inutile di memoria), solo mandrini la logica di filtraggio nel ciclo foreach. Questo qui non è esattamente quello che il codice viene tradotto, ma è una buona idea per concettualizzare come questo, con la condizione di filtro e ottenere fracassato all’interno del foreach.

Sotto il cofano, lo fa anteponendo la query per l’Enumeratore, e la restituzione di un Enumerabile che utilizza la logica da Cui() quando si chiama Enumerabile.MoveNext(). Se siete interessati, potete dare un’occhiata a come Sistema.Linq.Enumerabile maniglie in Sistema.Core.

Questo può effettivamente avere alcuni effetti negativi, se non stai attento. Che cosa succede se, tra il Dove() e l’esecuzione, la collezione è stata modificata? Ciò potrebbe causare una query essere eseguito l’ordine.

Per esempio, consente di dare questa stessa funzione di alcuni input, ma piuttosto che la stampa di destra di distanza, staremo a aggiungere una nuova parola per la lista prima del foreach. A prima vista questo può sembrare filtrare le singole lettere e di uscita “Ciao Mondo”, ma in realtà le uscite “Ciao Mondo di Banana,” perché il filtro non avere applicato fino MoveNext è chiamato durante l’iterazione del foreach.

Questo è particolarmente subdolo, poiché non siamo nemmeno toccare il toPrint variabile che viene passata al ciclo foreach. Tuttavia, se invece si accoda .ToList() alla fine della funzione, che costringerà C# per eseguire un’iterazione e restituire una nuova lista. A meno che specificamente quello che vuoi, però, è quasi sempre meglio risparmiare sul tempo di esecuzione e le assegnazioni heap utilizzando foreach con un Enumerabile.

Quali Sono Coroutines?

Coroutines sono funzioni speciali che può sospendere l’esecuzione e tornare al thread principale. Sono comunemente utilizzati per l’esecuzione di azioni a lungo che può richiedere un certo tempo per completare, senza causare il blocco dell’applicazione durante l’attesa della routine. Per esempio, nei giochi in cui la frequenza di applicazione, conta molto, grandi intoppi, anche dell’ordine di pochi millisecondi sarebbe male l’esperienza dell’utente.

Coroutines sono collegate abbastanza da vicino per Enumeratori, dal momento che sono in realtà solo le funzioni che restituiscono un enumeratore. Questo definisce un iteratore metodo, ed è possibile utilizzare questo. Non devi fare molto, basta cambiare il tipo di ritorno della funzione IEnumerator, e piuttosto che tornare a qualcosa, si può semplicemente resa, che automaticamente lo definisce come un enumeratore senza esplicitamente di farlo.

Quindi, per rompere l’esecuzione su diversi fotogrammi, ti basta resa return null se desideri sospendere l’esecuzione ed eseguire più thread principale. Quindi, utilizzare questo Enumeratore, è necessario chiamare la funzione e assegnarlo a una variabile, che è possibile chiamare il metodo MoveNext() a intervalli regolari.

Se si utilizza l’Unità, hanno una coroutine controller in grado di gestire l’elaborazione di coroutines per voi, solo la partenza e l’arresto con i loro metodi. Tuttavia, tutto ciò che sta realmente facendo è solo chiamando il metodo MoveNext() una volta per fotogramma, di verificare se è in grado di elaborare più, e la manipolazione il valore di ritorno se non è null. Si può gestire se stessi abbastanza facilmente:

Naturalmente, si potrebbe desiderare di funzionalità aggiuntive, come rendersi bambino coroutines cui dovrete aggiungere una elaborazione stack, e producendo espressioni come WaitForSeconds o in attesa per async funzioni di finitura, che avrete solo bisogno di verificare una volta per fotogramma (prima di chiamare il metodo MoveNext) se l’espressione restituisce true, e poi continuare l’elaborazione. In quel modo, la coroutine di fermare completamente fino a quando si può iniziare a correre di nuovo.