Istruzioni di iterazione: for
, foreach
, do
e while
Le istruzioni di iterazione eseguono ripetutamente un'istruzione o un blocco di istruzioni. L'istruzione for
esegue il corpo mentre un'espressione booleana specificata restituisce true
. L'istruzione foreach
enumera gli elementi di una raccolta ed esegue il corpo per ogni elemento della raccolta. L'istruzione do
esegue il corpo in modo condizionale una o più volte. L'istruzione while
esegue il corpo in modo condizionale zero o più volte.
In qualsiasi momento all'interno del corpo di un'istruzione di iterazione, è possibile interrompere il ciclo usando l'istruzione break
. È possibile passare all'iterazione successiva nel ciclo usando l'istruzione continue
.
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
:
La sezione initializer che viene eseguita una sola volta, prima dell'avvio del ciclo. In genere, in tale sezione si dichiara e inizializza una variabile di ciclo locale. Non è possibile accedere alla variabile dichiarata dall'esterno dell'istruzione
for
.La sezione initializer nell'esempio precedente dichiara e inizializza una variabile di contatore integer:
int i = 0
La sezione condition 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 condition, se presente, deve essere un'espressione booleana.La sezione condition nell'esempio precedente controlla se un valore del contatore è minore di tre:
i < 3
La sezione iterator definisce cosa accade dopo ogni iterazione del corpo del ciclo.
La sezione iterator nell'esempio precedente incrementa il contatore:
i++
Il corpo del ciclo che deve essere un'istruzione o un blocco di istruzioni.
La sezione iterator può contenere zero o più delle 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
- espressione
await
- creazione di un oggetto con l'operatore
new
Se non si dichiara una variabile di ciclo nella sezione initializer, è possibile usare zero o più espressioni dell'elenco precedente nella sezione initializer. L'esempio seguente illustra alcuni utilizzi meno comuni delle sezioni dell'istruzione initializer e iterator: assegnazione di un valore a una variabile di ciclo esterna nella sezione initializer, chiamata di un metodo sia nella sezione initializer che nella sezione iterator e modifica dei valori di due variabili nella sezione iterator:
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. L'esempio seguente definisce il ciclo for
infinito:
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:
List<int> fibNumbers = new() { 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 usarla con un'istanza di qualsiasi tipo che soddisfi le condizioni seguenti:
- Un tipo ha il metodo
GetEnumerator
pubblico senza parametri. Il metodoGetEnumerator
può essere anche un metodo di estensione del tipo. - Il tipo restituito del metodo
GetEnumerator
include la proprietàCurrent
pubblica e il metodoMoveNext
pubblico senza parametri con tipo restituitobool
.
L'esempio seguente usa l'istruzione foreach
con un'istanza del tipo System.Span<T>, che non implementa alcuna interfaccia:
Span<int> numbers = [3, 14, 15, 92, 6];
foreach (int number in numbers)
{
Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6
Se la proprietà Current
dell'enumeratore restituisce un valore restituito di riferimento (ref T
dove T
è il tipo dell'elemento della raccolta), è possibile dichiarare la variabile di iterazione con il modificatore ref
o ref readonly
, come illustrato nel metodo 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 viene 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. L'esempio seguente mostra come usare l'istruzione await foreach
:
await foreach (var item in GenerateSequenceAsync())
{
Console.WriteLine(item);
}
È anche possibile usare l'istruzione await foreach
con un'istanza di qualsiasi tipo che soddisfi le condizioni seguenti:
- Un tipo ha il metodo
GetAsyncEnumerator
pubblico senza parametri. Il metodo può essere anche un metodo di estensione del tipo. - Il tipo restituito del metodo
GetAsyncEnumerator
ha la proprietàCurrent
pubblica e il metodoMoveNextAsync
pubblico senza parametri il cui tipo restituito èTask<bool>
,ValueTask<bool>
o qualsiasi altro tipo awaitable il cui metodoGetResult
dell'awaiter restituisce un valorebool
.
Per impostazione predefinita, gli elementi del flusso vengono elaborati nel contesto acquisito. Se si vuole disabilitare l'acquisizione del contesto, usare il metodo di estensione TaskAsyncEnumerableExtensions.ConfigureAwait. 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 sui flussi asincroni.
Tipo di variabile di iterazione
È possibile usare la parola chiave var
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) { }
Nota
Il tipo di var
può essere dedotto dal compilatore come tipo riferimento nullable, a seconda che il contesto con riconoscimento nullable sia abilitato e se il tipo di un'espressione di inizializzazione sia un tipo riferimento.
Per altre informazioni, vedere Variabili locali tipizzate in modo implicito.
È 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 convertibile in modo implicito o esplicito nel tipo V
di una 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 uno che non implementa T
. In fase di esecuzione, il tipo di un elemento della raccolta può essere uno che deriva da T
e implementa effettivamente V
. 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 ciclo do
è diverso dal ciclo while
, che viene eseguito zero o più volte.
L'esempio seguente illustra 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 ciclo while
è diverso dal ciclo do
, che viene eseguito una o più volte.
L'esempio seguente illustra 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 su queste funzionalità, vedere le note sulla proposta di funzionalità seguenti: