foreach, in (справочник по C#)foreach, in (C# reference)

Оператор foreach выполняет оператор или блок операторов для каждого элемента в экземпляре типа, который реализует интерфейс System.Collections.IEnumerable или System.Collections.Generic.IEnumerable<T>, как показано в следующем примере.The foreach statement executes a statement or a block of statements for each element in an instance of the type that implements the System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T> interface, as the following example shows:

var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 };
int count = 0;
foreach (int element in fibNumbers)
{
    count++;
    Console.WriteLine($"Element #{count}: {element}");
}
Console.WriteLine($"Number of elements: {count}");

Оператор foreach не ограничен этими типами.The foreach statement isn't limited to those types. Его можно использовать с экземпляром любого типа, который удовлетворяет следующим условиям:You can use it with an instance of any type that satisfies the following conditions:

  • тип содержит открытый метод GetEnumerator без параметров со следующим типом возвращаемого значения: класс, структура или тип интерфейса.A type has the public parameterless GetEnumerator method whose return type is either class, struct, or interface type. Начиная с C# 9.0 метод GetEnumerator может быть методом расширения типа.Beginning with C# 9.0, the GetEnumerator method can be a type's extension method.
  • тип возвращаемого значения метода GetEnumerator должен содержать открытое свойство Current и открытый метод MoveNext без параметров с типом возвращаемого значения Boolean.The return type of the GetEnumerator method has the public Current property and the public parameterless MoveNext method whose return type is Boolean.

В следующем примере показано использование оператора foreach с экземпляром типа System.Span<T>, который не реализует интерфейс:The following example uses the foreach statement with an instance of the System.Span<T> type, which doesn't implement any interfaces:

public class IterateSpanExample
{
    public static void Main()
    {
        Span<int> numbers = new int[] { 3, 14, 15, 92, 6 };
        foreach (int number in numbers)
        {
            Console.Write($"{number} ");
        }
        Console.WriteLine();
    }
}

Начиная с версии C# 7.3, если свойство перечислителя Current возвращает ссылочное возвращаемое значение (ref T, где T — это тип элемента коллекции), вы можете объявить переменную итерации с модификатором ref или ref readonly, как показано в следующем примере.Beginning with C# 7.3, if the enumerator's Current property returns a reference return value (ref T where T is the type of a collection element), you can declare an iteration variable with the ref or ref readonly modifier, as the following example shows:

public class ForeachRefExample
{
    public static void Main()
    {
        Span<int> storage = stackalloc int[10];
        int num = 0;
        foreach (ref int item in storage)
        {
            item = num++;
        }

        foreach (ref readonly var item in storage)
        {
            Console.Write($"{item} ");
        }
        // Output:
        // 0 1 2 3 4 5 6 7 8 9
    }
}

Начиная с C# 8.0, можно применять оператор await foreach для использования асинхронного потока данных, то есть типа коллекции, реализующего интерфейс IAsyncEnumerable<T>.Beginning with C# 8.0, you can use the await foreach statement to consume an asynchronous stream of data, that is, the collection type that implements the IAsyncEnumerable<T> interface. Каждую итерацию цикла можно приостановить, пока будет осуществляться асинхронное извлечение следующего элемента.Each iteration of the loop may be suspended while the next element is retrieved asynchronously. В следующем примере показано использование оператора await foreach.The following example shows how to use the await foreach statement:

await foreach (var item in GenerateSequenceAsync())
{
    Console.WriteLine(item);
}

Элементы потока по умолчанию обрабатываются в захваченном контексте.By default, stream elements are processed in the captured context. Чтобы отключить захват контекста, используйте метод расширения TaskAsyncEnumerableExtensions.ConfigureAwait.If you want to disable capturing of the context, use the TaskAsyncEnumerableExtensions.ConfigureAwait extension method. Дополнительные сведения о контекстах синхронизации и захвате текущего контекста см. в статье Использование асинхронного шаблона, основанного на задачах.For more information about synchronization contexts and capturing the current context, see Consuming the Task-based asynchronous pattern. Дополнительные сведения об асинхронных потоках см. в разделе Асинхронные потоки статьи Новые возможности в C# 8.0.For more information about asynchronous streams, see the Asynchronous streams section of the What's new in C# 8.0 article.

В любой момент в блоке операторов foreach вы можете прервать цикл с помощью оператора break или перейти к следующей итерации в цикле с помощью оператора continue.At any point within the foreach statement block, you can break out of the loop by using the break statement, or step to the next iteration in the loop by using the continue statement. Можно также выйти из цикла foreach с помощью операторов goto, return или throw.You can also exit a foreach loop by the goto, return, or throw statements.

Если оператор foreach применяется к null, возникает исключение NullReferenceException.If the foreach statement is applied to null, a NullReferenceException is thrown. Если исходная коллекция инструкции foreach пустая, тело цикла foreach не выполняется и пропускается.If the source collection of the foreach statement is empty, the body of the foreach loop isn't executed and skipped.

Тип переменной итерацииType of an iteration variable

Можно использовать ключевое слово var, чтобы компилятор мог определить тип переменной итерации в операторе foreach, как показано в следующем коде:You can use the var keyword to let the compiler infer the type of an iteration variable in the foreach statement, as the following code shows:

foreach (var item in collection) { }

Можно также явно указать тип переменной итерации, как показано в следующем коде:You can also explicitly specify the type of an iteration variable, as the following code shows:

IEnumerable<T> collection = new T[5];
foreach (V item in collection) { }

В предыдущей форме тип T элемента коллекции должен быть неявно или явно преобразован в тип V переменной итерации.In the preceding form, type T of a collection element must be implicitly or explicitly convertible to type V of an iteration variable. Если явное преобразование из T в V завершается ошибкой во время выполнения, оператор foreach выдает исключение InvalidCastException.If an explicit conversion from T to V fails at run time, the foreach statement throws an InvalidCastException. Например, если T является незапечатанным типом класса, V может быть любым типом интерфейса, даже тем, который T не реализует.For example, if T is a non-sealed class type, V can be any interface type, even the one that T doesn't implement. Во время выполнения тип элемента коллекции может быть производным от T и фактически реализовать V.At run time, the type of a collection element may be the one that derives from T and actually implements V. В противном случае возникает InvalidCastException.If that's not the case, an InvalidCastException is thrown.

Спецификация языка C#C# language specification

Дополнительные сведения см. в разделе Оператор foreach в документации Предварительная спецификация C# 6.0.For more information, see The foreach statement section of the C# language specification.

Дополнительные сведения о функциях, добавленных в C# 8.0 и более поздние версии, см. в следующих заметках о функциях.For more information about features added in C# 8.0 and later, see the following feature proposal notes:

См. такжеSee also