Инструкция For Each... Next (Visual Basic)
Обновлен: Июль 2008
Повторяет группу операторов применительно к каждому элементу коллекции.
For Each element [ As datatype ] In group
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
Компоненты
element
Обязателен в операторе For Each. Необязателен в операторе Next. Переменная. Используется для циклического прохода (итерации) элементов коллекции.datatype
Обязателен, если еще не объявлен элемент element. Тип данных element.group
Обязательный компонент. Объектная переменная. Указывает на коллекцию, применительно к элементам которой будут повторяться операторы statements.statements
Необязательный компонент. Один или несколько операторов, стоящих между операторами For Each и Next и выполняющихся применительно к каждому элементу group.Exit For
Необязательный компонент. Передача управления из цикла For Each.Next
Обязательный компонент. Завершение определения цикла For Each.
Заметки
Цикл For Each...Next используется при необходимости повтора набора инструкций для каждого элемента коллекции или массива.
Оператор Инструкция For... Next (Visual Basic) работает лучше, когда можно связать каждую итерацию цикла с управляющей переменной и определить ее начальное и конечное значения. Тем не менее, при работе с коллекциями концепция начального и конечного значений не имеет смысла, а количество элементов в коллекции может быть неизвестно. В этом случае цикл For Each...Next является наилучшим выбором.
Правила
Типы данных. Тип данных element должен быть таким, чтобы тип данных элементов в group мог быть преобразован к нему.
Тип данных group должен быть ссылочным типом, указывающим на коллекцию или массив. Это означает, что group должен ссылаться на объект, реализующий интерфейс IEnumerable из пространства имен System.Collections или интерфейс IEnumerable<T> из пространства именSystem.Collections.Generic. В интерфейсе IEnumerable определен метод GetEnumerator, который возвращает объект перечислителя для коллекции. Объект перечислителя реализует интерфейс IEnumerator пространства имен System.Collections, а также имеет свойство Current, методы Reset и MoveNext. Visual Basic использует их для перемещения по коллекции.
Элементы group обычно относятся к типу Object, но могут также иметь любой тип данных времени выполнения.
Сужающие преобразования. Если Option Strict равно On, сужающее преобразование обычно вызывает ошибки компилятора. В следующем примере назначение m в качестве начального значения для n не компилируется с Option Strict так как преобразование Long в Integer является сужающим преобразованием.
Dim m As Long = 987 ' Does not compile. 'Dim n As Integer = m
Однако, преобразования из элементов группы group в element происходят во время выполнения и ошибка сужающего преобразования может быть неожиданной. В следующем примере не происходит ошибок компилятора в цикле For Each, несмотря на то, что требуется проделать то же самое преобразование из Long в Integer, что вызвало ошибку в предыдущем примере.
Option Strict On Module Module1 Sub Main() ' The assignment of m to n causes a compiler error when ' Option Strict is on. Dim m As Long = 987 'Dim n As Integer = m ' The For Each loop requires the same conversion, but ' causes no errors. The output is 45 3 987. For Each p As Integer In New Long() {45, 3, 987} Console.Write(p & " ") Next Console.WriteLine() End Sub End Module
Отсутствие ошибки при компиляции не уменьшает до нуля риск возникновения ошибки во время выполнения. В следующем примере компилятор не сообщает об ошибке, но ошибка во время выполнения происходит, когда преобразование ToInteger применяется к 9876543210. Ошибка во время выполнения происходит независимо включения ограничений Option Strict.
Option Strict On Module Module1 Sub Main() ' The assignment of m to n causes a compiler error when ' Option Strict is on. Dim m As Long = 9876543210 'Dim n As Integer = m Try ' The For Each loop requires the same conversion, but ' is not flagged by the compiler. A run-time error is ' raised because 9876543210 is too large for type Integer. For Each p As Integer In New Long() {45, 3, 9876543210} Console.Write(p & " ") Next Console.WriteLine() Catch e As System.OverflowException Console.WriteLine() Console.WriteLine(e.Message) End Try End Sub End Module
Объявление. Если element не был объявлен вне цикла, то его нужно объявить в операторе For Each. Можно объявить тип element явным образом при помощи оператора As, или можно использовать определение типа для назначения типа. В этом случае областью действия element является основная часть цикла. В то же время нельзя определять element и внутри, и снаружи цикла.
Число итераций. Visual Basic вычисляет коллекцию только один раз — перед началом цикла. Если в блоке операторов изменяется element или group, то эти изменения не оказывает влияния на повторение цикла.
Вложенные циклы. Циклы For Each могут быть вложенными. При этом каждый цикл должен иметь уникальную переменную element.
Также можно делать вложенными различные виды управляющих структур. Дополнительные сведения см. в разделе Вложенные структуры управления.
Примечание. Если инструкция Next внешнего уровня вложенности встретилась раньше, чем Next внутреннего уровня, то компилятор сообщает об ошибке. При этом компилятор может обнаружить эту ошибку только в том случае, если в каждой инструкции Next указан element.
Определение управляющих переменных. Можно дополнительно указать element в инструкции Next. Это повышает удобочитаемость программы, особенно если в ней имеются вложенные циклы For Each. При этом следует указать ту же переменную, что и в соответствующем операторе For Each.
Выход из цикла.Оператор Exit (Visual Basic) немедленно передает управление оператору, следующему за оператором Next. Выход из цикла может потребоваться при обнаружении условия, которое делает бесполезным или невозможным продолжение итераций, например ошибочное значение или запрос на завершение. Кроме того, если происходит перехват исключения в инструкции Try...Catch...Finally, то Exit For можно использовать в конце блока Finally.
Можно установить любое число операторов Exit For в любом месте цикла For Each. Exit For часто используется после определения некоторого условия, например в структуре If...Then...Else.
**Бесконечные циклы.**Exit For, в частности, применяется для тестирования условия, которое может вызвать бесконечный цикл, т. е. цикл, повторяемый очень много раз или бесконечно. При обнаружении таких условий для выхода из цикла можно использовать Exit For. Дополнительные сведения см. в разделе Оператор Do...Loop (Visual Basic).
Поведение
Вход в цикл. В начале выполнения цикла For Each...Next Visual Basic проверяет, на допустимую ли коллекцию объектов ссылается group. Если это не так, то создается исключение. В противном случае вызывается метод MoveNext и свойство Current объекта перечислителя, возвращающее первый элемент. Если MoveNext указывает, что следующий элемент отсутствует, то есть коллекция пуста, то цикл For Each завершается и управление передается оператору, следующему за оператором Next. В противном случае Visual Basic присваивает element значение первого элемента и выполняет блок операторов.
Итерации цикла. Каждый раз, обнаруживая инструкцию Next, Visual Basic возвращается на инструкцию For Each. Cнова для получения следующего элемента вызывается метод MoveNext и свойство Current, и снова в зависимости от результата либо выполняется блок, либо цикл завершается. Этот процесс продолжается до тех пор, пока метод MoveNext не укажет на отсутствие следующего элемента, или пока не встретится оператор Exit For.
Завершение цикла. Когда переменной element будут присвоены все элементы коллекции, цикл For Each завершится и управление будет передано оператору, следующему за оператором Next.
Изменение итерационных значений. Изменение значения element внутри тела цикла может осложнить читаемость и отладку кода. Изменение значения group не влияет на коллекцию или ее элементы, которые были определены в начале цикла.
Порядок обхода. При выполнении цикла For Each...Next обход коллекции выполняется под управлением объекта перечислителя, возвращаемого методом GetEnumerator. Порядок прохождения определяется не Visual Basic, а методом MoveNext объекта перечислителя. Это означает, что пользователь не может задать, какой элемент должен быть первым записан в element, или какой элемент должен следовать за каким-либо элементом.
Если код зависит от порядка обхода коллекции, то цикл For Each...Next имеет смысл применять только при известных характеристиках объекта перечислителя, предоставляемого коллекцией. С помощью другой циклической структуры, например For...Next или Do...Loop, можно добиться более надежных результатов.
Изменение коллекции. Объект перечислителя, возвращаемый GetEnumerator, не позволяет изменить коллекцию, добавляя, удаляя, заменяя элементы или изменяя порядок элементов. Если пользователь изменит коллекцию после запуска цикла For Each...Next, то объект перечислителя станет недействительным, и следующая попытка обращения к элементу коллекции вызовет исключение InvalidOperationException.
Однако эта блокировка изменения определяется не Visual Basic, а реализацией интерфейса IEnumerable. Можно реализовать IEnumerable таким образом, чтобы сделать изменение коллекции во время итерации возможным. Если планируется производить такие динамические изменения, то необходимо определить характер реализации IEnumerable используемой коллекции.
Изменение элементов коллекции. Свойство объекта перечисления Current имеет модификатор ReadOnly (Visual Basic) и возвращает локальную копию каждого элемента коллекции. Это означает, что в цикле For Each...Next нельзя изменить сами элементы. Любое изменение влияет только на локальную копию из Current и не отражается на коллекции. Тем не менее, если элемент имеет ссылочный тип, то можно изменять члены экземпляра, на который он указывает. Это показано в приведенном ниже примере.
Sub lightBlueBackground(ByVal thisForm As System.Windows.Forms.Form) For Each thisControl As System.Windows.Forms.Control In thisForm.Controls thisControl.BackColor = System.Drawing.Color.LightBlue Next thisControl End Sub
В предыдущем примере можно изменить член BackColor каждого элемента thisControl, несмотря на то, что нельзя изменить сам thisControl .
Обход массива. Поскольку класс Array реализует интерфейс IEnumerable, все массивы имеют метод GetEnumerator. Это означает, что с помощью цикла For Each... Next можно перебирать и массивы. Тем не менее, элементы массива можно только считывать, но не изменять их. Пример см. в разделе Практическое руководство. Запуск нескольких операторов для каждого элемента в коллекции или массиве.
Пример
В следующем примере конструкция For Each...Next используется для поиска строки "Hello" во всех элементах коллекции. В примере предполагается, что коллекция thisCollection уже была создана и ее элементы имеют тип String.
Dim found As Boolean = False
Dim thisCollection As New Collection
For Each thisObject As String In thisCollection
If thisObject = "Hello" Then
found = True
Exit For
End If
Next thisObject
См. также
Задачи
Практическое руководство. Запуск нескольких операторов для каждого элемента в коллекции или массиве
Практическое руководство. Улучшение быстродействия цикла
Основные понятия
Расширяющие и сужающие преобразования
Ссылки
Оператор While... End While (Visual Basic)
Оператор Do...Loop (Visual Basic)
Журнал изменений
Дата |
Журнал изменений |
Причина |
---|---|---|
Июль 2008 |
Добавлен подраздел о сужающих преобразованиях. |
Обратная связь от клиента. |