Istruzioni di iterazione - for
, foreach
, do
e while
Le istruzioni di iterazione eseguono ripetutamente un'istruzione o un blocco di istruzioni. L'istruzionefor
esegue il corpo mentre un'espressione booleana specificata restituisce true
. L'istruzioneforeach
enumera gli elementi di una raccolta ed esegue il relativo corpo per ogni elemento della raccolta. L'istruzionedo
esegue in modo condizionale il relativo corpo una o più volte. L'istruzionewhile
esegue in modo condizionale il corpo zero o più volte.
In qualsiasi punto all'interno del corpo di un'istruzione di iterazione, è possibile interrompere il ciclo usando l'istruzionebreak
. È possibile passare all'iterazione successiva nel ciclo usando l'istruzionecontinue
.
Istruzione for
L'istruzione for
esegue un'istruzione o un blocco di istruzioni mentre un'espressione booleana specificata restituisce true
. L'esempio seguente mostra l'istruzione for
che esegue il corpo mentre un contatore integer è minore di tre:
for (int i = 0; i < 3; i++)
{
Console.Write(i);
}
// Output:
// 012
L'esempio precedente mostra gli elementi dell'istruzione for
:
Sezione dell'inizializzatore eseguita una sola volta, prima di immettere il ciclo. In genere, si dichiara e inizializza una variabile di ciclo locale in tale sezione. Non è possibile accedere alla variabile dichiarata dall'esterno dell'istruzione
for
.La sezione inizializzatore nell'esempio precedente dichiara e inizializza una variabile del contatore integer:
int i = 0
Sezione della condizione che determina se deve essere eseguita l'iterazione successiva nel ciclo. Se restituisce
true
o non è presente, viene eseguita l'iterazione successiva; in caso contrario, il ciclo viene chiuso. La sezione della condizione deve essere un'espressione booleana.La sezione condition nell'esempio precedente controlla se un valore del contatore è minore di tre:
i < 3
Sezione iteratore che definisce cosa accade dopo ogni esecuzione del corpo del ciclo.
La sezione iteratore nell'esempio precedente incrementa il contatore:
i++
Corpo del ciclo, che deve essere un'istruzione o un blocco di istruzioni.
La sezione iteratore può contenere zero o più espressioni di istruzione seguenti, separate da virgole:
- Espressione di incremento in forma prefissa o suffissa, ad esempio
++i
oi++
- Espressione di decremento in forma prefissa o suffissa, ad esempio
--i
oi--
- Assegnazione
- Chiamata di un metodo
await
Espressione- creazione di un oggetto utilizzando l'operatore
new
Se non si dichiara una variabile di ciclo nella sezione inizializzatore, è possibile usare zero o più espressioni dell'elenco precedente nella sezione inizializzatore. Nell'esempio seguente vengono illustrati diversi utilizzi meno comuni delle sezioni inizializzatore e iteratore: assegnazione di un valore a una variabile esterna nella sezione inizializzatore, richiamo di un metodo nelle sezioni inizializzatore e iteratore e modifica dei valori di due variabili nella sezione iteratore:
int i;
int j = 3;
for (i = 0, Console.WriteLine($"Start: i={i}, j={j}"); i < j; i++, j--, Console.WriteLine($"Step: i={i}, j={j}"))
{
//...
}
// Output:
// Start: i=0, j=3
// Step: i=1, j=2
// Step: i=2, j=1
Tutte le sezioni dell'istruzione for
sono facoltative. Ad esempio, il codice seguente definisce il ciclo infinito for
:
for ( ; ; )
{
//...
}
Istruzione foreach
L'istruzione foreach
esegue un'istruzione o un blocco di istruzioni per ogni elemento in un'istanza del tipo che implementa l'interfaccia System.Collections.IEnumerable o System.Collections.Generic.IEnumerable<T> , come illustrato nell'esempio seguente:
var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 };
foreach (int element in fibNumbers)
{
Console.Write($"{element} ");
}
// Output:
// 0 1 1 2 3 5 8 13
L'istruzione foreach
non è limitata a questi tipi. È possibile usarlo con un'istanza di qualsiasi tipo che soddisfi le condizioni seguenti:
- Un tipo ha il metodo pubblico senza
GetEnumerator
parametri. A partire da C# 9.0, ilGetEnumerator
metodo può essere un metodo di estensione di un tipo. - Il tipo restituito del
GetEnumerator
metodo ha la proprietà publicCurrent
e il metodo pubblico senzaMoveNext
parametri il cui tipo restituito èbool
.
Nell'esempio seguente viene usata l'istruzione con un'istanza foreach
del System.Span<T> tipo , che non implementa interfacce:
Span<int> numbers = new int[] { 3, 14, 15, 92, 6 };
foreach (int number in numbers)
{
Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6
Se la proprietà dell'enumeratore Current
restituisce un valore restituito di riferimento (ref T
dove T
è il tipo di un elemento della raccolta), è possibile dichiarare una variabile di iterazione con il ref
modificatore o ref readonly
, come illustrato nell'esempio seguente:
Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
item = num++;
}
foreach (ref readonly var item in storage)
{
Console.Write($"{item} ");
}
// Output:
// 0 1 2 3 4 5 6 7 8 9
Se la raccolta di origine dell'istruzione foreach
è vuota, il corpo dell'istruzione foreach
non viene eseguito e ignorato. Se l'istruzione foreach
viene applicata a null
, viene generata una NullReferenceException.
await foreach
È possibile usare l'istruzione await foreach
per utilizzare un flusso asincrono di dati, ovvero il tipo di raccolta che implementa l'interfaccia IAsyncEnumerable<T> . Ogni iterazione del ciclo può essere sospesa mentre l'elemento successivo viene recuperato in modo asincrono. Nell'esempio seguente viene illustrato come usare l'istruzione await foreach
:
await foreach (var item in GenerateSequenceAsync())
{
Console.WriteLine(item);
}
È anche possibile usare l'istruzione con un'istanza await foreach
di qualsiasi tipo che soddisfi le condizioni seguenti:
- Un tipo ha il metodo pubblico senza
GetAsyncEnumerator
parametri. Questo metodo può essere il metodo di estensione di un tipo. - Il tipo restituito del
GetAsyncEnumerator
metodo ha la proprietà publicCurrent
e il metodo pubblico senzaMoveNextAsync
parametri il cui tipo restituito èTask<bool>
,ValueTask<bool>
o qualsiasi altro tipo awaitable ilGetResult
cui metodo awaiter restituisce unbool
valore.
Per impostazione predefinita, gli elementi del flusso vengono elaborati nel contesto acquisito. Se si vuole disabilitare l'acquisizione del contesto, usare il TaskAsyncEnumerableExtensions.ConfigureAwait metodo di estensione. Per altre informazioni sui contesti di sincronizzazione e sull'acquisizione del contesto corrente, vedere Utilizzo del modello asincrono basato su attività. Per altre informazioni sui flussi asincroni, vedere l'esercitazione Flussi asincroni.
Tipo di variabile di iterazione
È possibile usare la var
parola chiave per consentire al compilatore di dedurre il tipo di una variabile di iterazione nell'istruzione foreach
, come illustrato nel codice seguente:
foreach (var item in collection) { }
È anche possibile specificare in modo esplicito il tipo di una variabile di iterazione, come illustrato nel codice seguente:
IEnumerable<T> collection = new T[5];
foreach (V item in collection) { }
Nel formato precedente, il tipo T
di un elemento della raccolta deve essere implicitamente o esplicitamente convertibile in un tipo V
di variabile di iterazione. Se una conversione esplicita da T
a V
ha esito negativo in fase di esecuzione, l'istruzione foreach
genera un'eccezione InvalidCastException. Ad esempio, se T
è un tipo di classe non sealed, V
può essere qualsiasi tipo di interfaccia, anche quello che T
non implementa. In fase di esecuzione, il tipo di un elemento di raccolta può essere quello che deriva da T
e implementa V
effettivamente . In caso contrario, viene generata un'eccezione InvalidCastException .
Istruzione do
L'istruzione do
esegue un'istruzione o un blocco di istruzioni mentre un'espressione booleana specificata restituisce true
. Poiché tale espressione viene valutata dopo ogni esecuzione del ciclo, un ciclo do
viene eseguito una o più volte. Il do
ciclo differisce dal while
ciclo , che esegue zero o più volte.
Nell'esempio seguente viene illustrato l'utilizzo dell'istruzione do
:
int n = 0;
do
{
Console.Write(n);
n++;
} while (n < 5);
// Output:
// 01234
Istruzione while
L'istruzione while
esegue un'istruzione o un blocco di istruzioni mentre un'espressione booleana specificata restituisce true
. Poiché tale espressione viene valutata prima di ogni esecuzione del ciclo, un ciclo while
viene eseguito zero o più volte. Il while
ciclo è diverso dal do
ciclo , che esegue una o più volte.
Nell'esempio seguente viene illustrato l'utilizzo dell'istruzione while
:
int n = 0;
while (n < 5)
{
Console.Write(n);
n++;
}
// Output:
// 01234
Specifiche del linguaggio C#
Per altre informazioni, vedere le sezioni seguenti delle specifiche del linguaggio C#:
Per altre informazioni sulle funzionalità aggiunte in C# 8.0 e versioni successive, vedere le note seguenti sulla proposta di funzionalità: