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

86

Какие типы классов могут использовать foreachциклы?

user48616
источник
5
Вы можете выбрать другой принятый ответ, поскольку тот, который вы выбрали, на самом деле не соответствует правильному ответу.
Джордж Стокер,

Ответы:

162

На самом деле, строго говоря, все, что вам нужно использовать, 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) {...}kinda означает:

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

Марк Гравелл
источник
3
+1 за углубление. Обычно я не углубляюсь в вопрос, который может быть вопросом «новичка», так как он покажется непосильным для нового программиста.
Джордж Стокер,
Верно, Горток - поэтому я продолжил работу со списками / массивами и т. Д.
Марк Гравелл
Было бы хорошо упомянуть неявное приведение во время выполнения к переменной цикла - это может привести к исключениям несовместимости типов.
Дэниел Эрвикер,
3
Не забывайте: при использовании массива с foreach компилятор создает простой for-loop(вы можете увидеть это при работе с IL).
Феликс К.
1
@Marc Gravell: Хорошо, круто! Я отредактировал сообщение, чтобы было понятнее - по крайней мере, для меня. В конце концов, размещение важно не только в C # 5.0, оно всегда важно, только то, что оно изменилось. Надеюсь, ты не против.
Пол Грок,
7

Из 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);
}
Джордж Стокер
источник
4
как ни странно, согласно MSDN ( msdn.microsoft.com/en-us/library/9yb8xew9(VS.80).aspx ), типы объектов не нуждаются в реализации IEnumerable. Подойдет любой тип, который правильно определяет GetEnumerator, MoveNext, Reset и Current. Странно, да?
Шон Рейли,
Аккуратно. Я этого не знал. :-)
Джордж Стокер
4

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

Tuinstoel
источник
2

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

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

Это вызовет исключение времени выполнения, если в корзине с фруктами есть не 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>() )
Эми Б
источник
-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

Полезную информацию по этой теме также можно найти на 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());
}
r23
источник
-2

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

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);
        }
Дедарул
источник