¿Cómo funcionan los bucles foreach en C #? [cerrado]

86

¿Qué tipos de clases pueden usar foreachbucles?

user48616
fuente
5
Es posible que desee elegir una respuesta aceptada diferente, ya que la que seleccionó no representa realmente la respuesta correcta.
George Stocker

Respuestas:

162

En realidad, estrictamente hablando, todo lo que necesita usar foreaches un GetEnumerator()método público que devuelva algo con un bool MoveNext()método y una ? Current {get;}propiedad. Sin embargo, el significado más común de esto es "algo que implementa IEnumerable/ IEnumerable<T>, devolviendo un IEnumerator/ IEnumerator<T>.

Por implicación, esto incluye cualquier cosa que implementa ICollection/ ICollection<T>, como por ejemplo algo como Collection<T>, List<T>, matrices ( T[]), etc. Por lo que cualquier "recopilación de datos" estándar generalmente apoyar foreach.

Como prueba del primer punto, lo siguiente funciona bien:

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);
        }
    }
}

¿Como funciona?

Un bucle foreach como foreach(int i in obj) {...}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
}

Sin embargo, existen variaciones. Por ejemplo, si el enumerador (tmp) lo admite IDisposable, también se usa (similar a using).

Tenga en cuenta la diferencia en la ubicación de la declaración " int i" dentro (C # 5.0) frente a fuera (hasta C # 4.0) del bucle. Es importante si usa iun método / lambda anónimo dentro de su bloque de código. Pero esa es otra historia ;-p

Marc Gravell
fuente
3
+1 por profundizar. Normalmente no profundizo tanto en una pregunta que puede ser una pregunta para "principiantes", ya que parecería abrumadora para el nuevo programador.
George Stocker
Es cierto, Gortok, así que seguí con las cosas sobre listas / matrices / etc.
Marc Gravell
Sería bueno mencionar la conversión implícita en tiempo de ejecución a la variable de bucle: puede producir excepciones de incompatibilidad de tipos.
Daniel Earwicker
3
No lo olvide: cuando usa una matriz con foreach, el compilador crea un simple for-loop(puede ver esto cuando trabaja con IL).
Felix K.
1
@Marc Gravell: ¡Bien, genial! Edité la publicación para que quede más claro, al menos para mí. Después de todo, la ubicación no solo es importante en C # 5.0, siempre es importante, solo que cambió. Espero que no te moleste.
Paul Groke
7

Desde MSDN :

La foreachdeclaración repite un grupo de declaraciones incrustadas para cada elemento de una matriz o colección de objetos . La foreachdeclaración se usa para iterar a través de la colección para obtener la información deseada, pero no debe usarse para cambiar el contenido de la colección para evitar efectos secundarios impredecibles. (énfasis mío)

Entonces, si tiene una matriz, puede usar la instrucción foreach para iterar a través de la matriz, así:

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

También puede usarlo para iterar a través de una List<T>colección, así:

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

foreach (string item in list)
{
    Console.WriteLine(item);
}
George Stocker
fuente
4
Curiosamente, según MSDN ( msdn.microsoft.com/en-us/library/9yb8xew9(VS.80).aspx ), los tipos de objetos no necesitan implementar IEnumerable. Cualquier tipo que defina GetEnumerator, MoveNext, Reset y Current de la forma correcta funcionará. Extraño, ¿eh?
Sean Reilly
Ordenado. Yo no lo sabía. :-)
George Stocker
4

De acuerdo con la publicación del blog Duck Notation , se usa la escritura de pato.

tuinstoel
fuente
2

Aquí están los documentos: Artículo principal con matrices con objetos de colección

Es importante tener en cuenta que "El tipo de elemento de la colección debe ser convertible al tipo de identificador". En ocasiones, esto no se puede comprobar en tiempo de compilación y puede generar una excepción en tiempo de ejecución si el tipo de instancia no se puede asignar al tipo de referencia.

Esto generará una excepción de tiempo de ejecución si hay una que no sea de Apple en la canasta de frutas, como una naranja.

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

Esto filtra de forma segura la lista solo a las manzanas usando Enumerable.OfType

foreach(Apple a in fruitBasket.OfType<Apple>() )
Amy B
fuente
-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);
    }
}
Shahzad
fuente
-1

También se puede encontrar información útil sobre este tema en MSDN . Tomando la esencia de ese artículo:

La palabra clave foreach enumera una colección, ejecutando la declaración incrustada una vez para cada elemento de la colección:

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

El compilador traduce el bucle foreach que se muestra en el ejemplo anterior en algo similar a esta construcción:

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

puedes probar esto ...

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);
        }
Dedarul
fuente