Как работают циклы 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);
}