Как работают циклы foreach в C#?

Какие типы классов можно использовать foreach петли?

7 ответов

На самом деле, строго говоря, все, что вам нужно использовать foreach является общественным GetEnumerator() метод, который возвращает что-то с bool MoveNext() метод и ? Current {get;} имущество. Тем не менее, наиболее распространенным значением этого является "то, что реализует IEnumerable/IEnumerable<T>, вернув IEnumerator/IEnumerator<T>,

Подразумевается, что это включает в себя все, что реализует ICollection/ICollection<T>типа чего-либо подобного Collection<T>, List<T>, массивы (T[]) и т. д. Таким образом, любой стандартный "сбор данных" обычно поддерживает foreach,

Для доказательства первого пункта просто отлично работает следующее:

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

Как это работает?

Цикл foreach как foreach(int i in obj) {...} своего рода приравнивается к:

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

Тем не менее, есть вариации. Например, это поддерживает перечислитель (tmp) IDisposableтоже используется (аналогично using).

Обратите внимание на разницу в размещении декларации "int i" Внутри (C# 5.0) и вне (до C# 4.0) цикла. Это важно, если вы используете i в анонимном методе / лямбда внутри вашего кода блока. Но это другая история;-p

Из MSDN:

foreach оператор повторяет группу встроенных операторов для каждого элемента в массиве или коллекции объектов. foreach Оператор используется для перебора коллекции для получения нужной информации, но не должен использоваться для изменения содержимого коллекции во избежание непредсказуемых побочных эффектов. (акцент мой)

Итак, если у вас есть массив, вы можете использовать оператор foreach для перебора массива следующим образом:

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

Вы также можете использовать его для перебора List<T> Коллекция, вот так:

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

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

Согласно сообщению в блоге Duck Notation, используется типирование утки.

Вот документы: Основная статья с массивами с объектами коллекции

Важно отметить, что "тип элемента коллекции должен быть преобразован в тип идентификатора". Иногда это не может быть проверено во время компиляции и может генерировать исключение во время выполнения, если тип экземпляра не может быть назначен ссылочному типу.

Это создаст исключение во время выполнения, если в корзине с фруктами не будет Apple, например апельсин.

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

Это безопасно фильтрует список только для яблок, использующих Enumerable.OfType

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

Цикл Foreach и как он перебирает IEnumerable под капотом.

Справочные примеры C# Foreach

Полезную информацию по этому вопросу можно найти и на MSDN. Принимая суть из этой статьи:

Ключевое слово foreach перечисляет коллекцию, выполняя встроенный оператор один раз для каждого элемента в коллекции:

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

Компилятор переводит цикл foreach, показанный в примере выше, во что-то похожее на эту конструкцию:

IEnumerator<int> enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
    var item = enumerator.Current;
    Console.WriteLine(item.ToString());
}
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);
    }
}

Вы можете попробовать это...

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);
        }
Другие вопросы по тегам