Come funzionano i cicli foreach in C #? [chiuso]


86

Quali tipi di classi possono utilizzare i foreachloop?


5
Puoi scegliere una risposta accettata diversa, poiché quella che hai selezionato non è realmente rappresentativa della risposta corretta.
George Stocker

Risposte:


162

In realtà, in senso stretto, tutto ciò che devi usare foreachè un GetEnumerator()metodo pubblico che restituisca qualcosa con un bool MoveNext()metodo e una ? Current {get;}proprietà. Tuttavia, il significato più comune di questo è "qualcosa che implementa IEnumerable/ IEnumerable<T>, restituendo un IEnumerator/ IEnumerator<T>.

Implicitamente, questo include tutto ciò che implementa ICollection/ ICollection<T>, come qualcosa di simile Collection<T>, List<T>, array ( T[]), ecc Quindi, qualsiasi "raccolta di dati" standard generalmente sostenere foreach.

Per la prova del primo punto, quanto segue funziona perfettamente:

using System;
class Foo {
    public int Current { get; private set; }
    private int step;
    public bool MoveNext() {
        if (step >= 5) return false;
        Current = step++;
        return true;
    }
}
class Bar {
    public Foo GetEnumerator() { return new Foo(); }
}
static class Program {
    static void Main() {
        Bar bar = new Bar();
        foreach (int item in bar) {
            Console.WriteLine(item);
        }
    }
}

Come funziona?

Un ciclo foreach come foreach(int i in obj) {...}un pò equivale a:

var tmp = obj.GetEnumerator();
int i; // up to C# 4.0
while(tmp.MoveNext()) {
    int i; // C# 5.0
    i = tmp.Current;
    {...} // your code
}

Tuttavia, ci sono variazioni. Ad esempio, se l'enumeratore (tmp) supporta IDisposable, viene utilizzato anche (simile a using).

Notare la differenza nel posizionamento della " int i" dichiarazione all'interno (C # 5.0) e all'esterno (su C # 4.0) del ciclo. È importante se usi iun metodo anonimo / lambda all'interno del tuo blocco di codice. Ma questa è un'altra storia ;-p


3
+1 per andare in profondità. Normalmente non vado così in profondità per una domanda che potrebbe essere una domanda "per principianti" poiché sembrerebbe opprimente al nuovo programmatore.
George Stocker

Vero, Gortok, quindi ho proseguito con le cose su liste / array / ecc.
Marc Gravell

Sarebbe utile menzionare il cast di runtime implicito alla variabile loop: può produrre eccezioni di incompatibilità di tipo.
Daniel Earwicker,

3
Non dimenticare: quando si utilizza un array con foreach, il compilatore crea un semplice for-loop(puoi vederlo quando lavori con IL).
Felix K.

1
@ Marc Gravell: OK, fantastico! Ho modificato il post per renderlo più chiaro, almeno per me. Dopo tutto il posizionamento non è importante solo in C # 5.0, è sempre importante, solo che è cambiato. Spero non ti dispiaccia.
Paul Groke

7

Da MSDN :

L' foreachistruzione ripete un gruppo di istruzioni incorporate per ogni elemento in un array o in una raccolta di oggetti . L' foreachistruzione viene utilizzata per scorrere la raccolta per ottenere le informazioni desiderate, ma non deve essere utilizzata per modificare il contenuto della raccolta per evitare effetti collaterali imprevedibili. (enfasi mia)

Quindi, se hai un array, puoi usare l'istruzione foreach per iterare attraverso l'array, in questo modo:

 int[] fibarray = new int[] { 0, 1, 2, 3, 5, 8, 13 };
    foreach (int i in fibarray)
    {
        System.Console.WriteLine(i);
    }

Puoi anche usarlo per scorrere una List<T>raccolta, in questo modo:

List<string> list = new List<string>();

foreach (string item in list)
{
    Console.WriteLine(item);
}

4
abbastanza stranamente, secondo MSDN ( msdn.microsoft.com/en-us/library/9yb8xew9(VS.80).aspx ), i tipi di oggetti non devono implementare IEnumerable. Qualsiasi tipo che definisce GetEnumerator, MoveNext, Reset e Current nel modo corretto funzionerà. Strano, eh?
Sean Reilly

Neat. Non lo sapevo. :-)
George Stocker,


2

Ecco i documenti: articolo principale con array con oggetti di raccolta

È importante notare che "Il tipo dell'elemento della raccolta deve essere convertibile nel tipo di identificatore". Questo a volte non può essere verificato in fase di compilazione e può generare un'eccezione di runtime se il tipo di istanza non è assegnabile al tipo di riferimento.

Questo genererà un'eccezione di runtime se nel cesto della frutta è presente una mela non, come un'arancia.

List<Fruit> fruitBasket = new List<Fruit>() { new Apple(), new Orange() };
foreach(Apple a in fruitBasket)

Questo filtra in modo sicuro l'elenco solo per le mele utilizzando Enumerable.OfType

foreach(Apple a in fruitBasket.OfType<Apple>() )

-1
IList<ListItem> illi = new List<ListItem>();
ListItem li = null;

foreach (HroCategory value in listddlsubcategory)
{
    listddlsubcategoryext = server.getObjectListByColumn(typeof(HroCategory), "Parentid", value.Id);
    li = new ListItem();
    li.Text = value.Description;
    li.Value = value.Id.ToString();
    illi.Add(li);
    IList<ListItem> newilli = new List<ListItem>();
    newilli = SubCatagoryFunction(listddlsubcategoryext, "-->");
    foreach (ListItem c in newilli)
    {
        illi.Add(c);
    }
}

-1

Informazioni utili su questo argomento si possono trovare anche su MSDN . Prendendo l'essenza da quell'articolo:

La parola chiave foreach enumera una raccolta, eseguendo l'istruzione incorporata una volta per ogni elemento nella raccolta:

foreach (var item in collection)
{
    Console.WriteLine(item.ToString());
}

Il compilatore traduce il ciclo foreach mostrato nell'esempio sopra in qualcosa di simile a questo costrutto:

IEnumerator<int> enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
    var item = enumerator.Current;
    Console.WriteLine(item.ToString());
}

-2

puoi provare questo ...

List<int> numbers = new List<int>();
        numbers.Add(5);
        numbers.Add(15);
        numbers.Add(25);
        numbers.Add(35);

        Console.WriteLine("You are added total number: {0}",numbers.Count);
        foreach (int number in numbers)
        {
            Console.WriteLine("Your adding Number are: {0}", number);
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.