Como os loops foreach funcionam em C #? [fechadas]

86

Quais tipos de classes podem usar foreachloops?

usuário 48616
fonte
5
Você pode escolher uma resposta aceita diferente, uma vez que aquela que você selecionou não representa realmente a resposta correta.
George Stocker

Respostas:

162

Na verdade, estritamente falando, tudo que você precisa usar foreaché um GetEnumerator()método público que retorna algo com um bool MoveNext()método e uma ? Current {get;}propriedade. No entanto, o significado mais comum disso é "algo que implementa IEnumerable/ IEnumerable<T>, retornando um IEnumerator/ IEnumerator<T>.

Por implicação, isso inclui qualquer coisa que implementa ICollection/ ICollection<T>, como qualquer coisa como Collection<T>, List<T>, matrizes ( T[]), etc. Assim, qualquer "recolha de dados" padrão geralmente apoiar foreach.

Para provar o primeiro ponto, o seguinte funciona perfeitamente:

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?

Um loop foreach como foreach(int i in obj) {...}meio que 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
}

No entanto, existem variações. Por exemplo, se o enumerador (tmp) for compatível IDisposable, ele também será usado (semelhante a using).

Observe a diferença na colocação da declaração " int i" dentro (C # 5.0) vs. fora (até C # 4.0) do loop. É importante se você usar iem um método anônimo / lambda dentro de seu bloco de código. Mas essa é outra história ;-p

Marc Gravell
fonte
3
1 para ir em profundidade. Normalmente não vou tão a fundo para uma questão que pode ser uma questão de 'iniciante', pois pareceria opressora para o novo programador.
George Stocker
Verdade, Gortok - então continuei com o material sobre listas / matrizes / etc.
Marc Gravell
Seria bom mencionar a conversão implícita de tempo de execução na variável de loop - pode produzir exceções de incompatibilidade de tipo.
Daniel Earwicker
3
Não se esqueça: ao usar um array com foreach, o compilador cria um simples for-loop(você pode ver isso ao trabalhar com IL).
Felix K.
1
@Marc Gravell: OK, legal! Eu editei a postagem para deixar mais claro - pelo menos para mim. Afinal, o posicionamento não é importante apenas no C # 5.0, é sempre importante, apenas que ele mudou. Espero que você não se importe.
Paul Groke
7

Do MSDN :

A foreachinstrução repete um grupo de instruções incorporadas para cada elemento em uma matriz ou coleção de objetos . A foreachinstrução é usada para iterar pela coleção para obter as informações desejadas, mas não deve ser usada para alterar o conteúdo da coleção para evitar efeitos colaterais imprevisíveis. (ênfase minha)

Portanto, se você tiver uma matriz, poderá usar a instrução foreach para iterar pela matriz, assim:

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

Você também pode usá-lo para iterar por meio de uma List<T>coleção, assim:

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

foreach (string item in list)
{
    Console.WriteLine(item);
}
George Stocker
fonte
4
curiosamente, de acordo com o MSDN ( msdn.microsoft.com/en-us/library/9yb8xew9(VS.80).aspx ), os tipos de objetos não precisam implementar IEnumerable. Qualquer tipo que defina GetEnumerator, MoveNext, Reset e Current da maneira correta funcionará. Estranho, hein?
Sean Reilly
Arrumado. Eu não sabia disso. :-)
George Stocker
4

De acordo com a postagem do blog Duck Notation , a digitação duck é usada.

tuinstoel
fonte
2

Aqui estão os documentos: Artigo principal com matrizes com objetos de coleção

É importante observar que "O tipo do elemento de coleção deve ser conversível para o tipo de identificador". Isso às vezes não pode ser verificado em tempo de compilação e pode gerar uma exceção de tempo de execução se o tipo de instância não puder ser atribuído ao tipo de referência.

Isso gerará uma exceção de tempo de execução se houver um não-Apple na cesta de frutas, como uma laranja.

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

Isso filtra com segurança a lista apenas para as maçãs usando Enumerable.OfType

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

Informações úteis sobre este assunto também podem ser encontradas no MSDN . Tirando a essência desse artigo:

A palavra-chave foreach enumera uma coleção, executando a instrução incorporada uma vez para cada elemento da coleção:

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

O compilador traduz o loop foreach mostrado no exemplo acima em algo semelhante a esta construção:

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

você pode tentar isso ...

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
fonte