コレクション内の各要素に対してステートメントのグループを繰り返します。
構文
For Each element [ As datatype ] In group
[ statements ]
[ Continue For ]
[ statements ]
[ Exit For ]
[ statements ]
Next [ element ]
部品
任期 | 定義 |
---|---|
element |
For Each ステートメントで必要です。
Next ステートメントでは省略可能です。 変数。 コレクションの要素を反復処理するために使用されます。 |
datatype |
Option Infer がオン (既定値) またはelement が既に宣言されている場合は省略可能です。Option Infer がオフで、element がまだ宣言されていない場合は必須です。
element のデータ型。 |
group |
必須。 コレクション型またはオブジェクト型の変数。
statements を繰り返すコレクションを参照します。 |
statements |
任意。
group の各項目で実行されるFor Each とNext の間の 1 つ以上のステートメント。 |
Continue For |
任意。
For Each ループの先頭に制御を転送します。 |
Exit For |
任意。
For Each ループから制御を転送します。 |
Next |
必須。
For Each ループの定義を終了します。 |
簡単な例
コレクションまたは配列の各要素に対してステートメントのセットを繰り返す場合は、 For Each
...Next
ループを使用します。
ヒント
A For...次のステートメントは、ループの各反復を制御変数に関連付け、その変数の初期値と最終値を決定できる場合に適切に機能します。 ただし、コレクションを扱う場合、初期値と最終値の概念は意味がなく、コレクションに含まれる要素の数が必ずしもわかりません。 このような場合、多くの場合、 For Each
...Next
ループが適しています。
次の例では、 For Each
...
Next
ステートメントは、List コレクションのすべての要素を反復処理します。
' Create a list of strings by using a
' collection initializer.
Dim lst As New List(Of String) _
From {"abc", "def", "ghi"}
' Iterate through the list.
For Each item As String In lst
Debug.Write(item & " ")
Next
Debug.WriteLine("")
'Output: abc def ghi
その他の例については、「 コレクション と 配列」を参照してください。
入れ子になったループ
For Each
ループを入れ子にするには、別のループ内にループを配置します。
次の例では、入れ子になった For Each
...
Next
構造体のメンバーです。
' Create lists of numbers and letters
' by using array initializers.
Dim numbers() As Integer = {1, 4, 7}
Dim letters() As String = {"a", "b", "c"}
' Iterate through the list by using nested loops.
For Each number As Integer In numbers
For Each letter As String In letters
Debug.Write(number.ToString & letter & " ")
Next
Next
Debug.WriteLine("")
'Output: 1a 1b 1c 4a 4b 4c 7a 7b 7c
ループを入れ子にする場合、各ループには一意の element
変数が必要です。
また、さまざまな種類のコントロール構造を相互に入れ子にすることもできます。 詳細については、「ネストされたコントロール構造」を参照してください。
Exit For と Continue For
Exit For ステートメントを実行すると、For
...
Next
ループし、 Next
ステートメントに続くステートメントに制御を転送します。
Continue For
ステートメントは、制御をループの次のイテレーションに直ちに転送します。 詳細については、「 Continue ステートメント」を参照してください。
次の例は、 Continue For
ステートメントと Exit For
ステートメントの使用方法を示しています。
Dim numberSeq() As Integer =
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
For Each number As Integer In numberSeq
' If number is between 5 and 8, continue
' with the next iteration.
If number >= 5 And number <= 8 Then
Continue For
End If
' Display the number.
Debug.Write(number.ToString & " ")
' If number is 10, exit the loop.
If number = 10 Then
Exit For
End If
Next
Debug.WriteLine("")
' Output: 1 2 3 4 9 10
For Each
ループには、任意の数のExit For
ステートメントを配置できます。 入れ子になった For Each
ループ内で使用すると、 Exit For
によって最も内側のループが終了し、制御が次の上位レベルの入れ子に転送されます。
Exit For
は、多くの場合、 If
...Then
など、何らかの条件の評価後に使用されます...Else
構造。 次の条件に対して Exit For
を使用できます。
繰り返し処理を続けることは不要または不可能です。 これは、誤った値または終了要求が原因である可能性があります。
例外が
Try
...Catch
でキャッチされる...Finally
。Finally
ブロックの末尾にExit For
を使用できます。無限ループがあります。これは、多数または無限の回数実行できるループです。 このような条件を検出した場合は、
Exit For
を使用してループをエスケープできます。 詳細については、Do...Loop ステートメントを参照してください。
反復子
反復子を使用して、コレクションに対してカスタムイテレーションを実行します。 反復子には、関数または Get
アクセサーを指定できます。
Yield
ステートメントを使用して、コレクションの各要素を一度に 1 つずつ返します。
For Each...Next
ステートメントを使用して反復子を呼び出します。
For Each
ループの各反復処理で反復子が呼び出されます。 反復子で Yield
ステートメントに到達すると、 Yield
ステートメント内の式が返され、コード内の現在の位置が保持されます。 次に反復子が呼び出されるときに、その場所から実行が再開されます。
次の例では、反復子関数を使用します。 反復子関数には、For... 内の Yield
ステートメントがあります 。次の ループ。
ListEvenNumbers
メソッドでは、For Each
ステートメント本体の各反復処理によって反復子関数の呼び出しが作成され、次の Yield
ステートメントに進みます。
Public Sub ListEvenNumbers()
For Each number As Integer In EvenSequence(5, 18)
Debug.Write(number & " ")
Next
Debug.WriteLine("")
' Output: 6 8 10 12 14 16 18
End Sub
Private Iterator Function EvenSequence(
ByVal firstNumber As Integer, ByVal lastNumber As Integer) _
As System.Collections.Generic.IEnumerable(Of Integer)
' Yield even numbers in the range.
For number = firstNumber To lastNumber
If number Mod 2 = 0 Then
Yield number
End If
Next
End Function
詳細については、「 反復子、 Yield ステートメント、反復子」を参照 してください。
技術的な実装
For Each
の場合...
Next
ステートメントを実行すると、ループが開始される前に、Visual Basic によってコレクションが 1 回だけ評価されます。 ステートメント ブロックが element
または group
に変更された場合、これらの変更はループの反復には影響しません。
コレクション内のすべての要素が element
に連続して割り当てられると、 For Each
ループは停止し、 Next
ステートメントの後のステートメントに制御が渡されます。
オプション推論がオン (既定の設定) の場合、Visual Basic コンパイラはelement
のデータ型を推論できます。 オフで、 element
がループの外部で宣言されていない場合は、 For Each
ステートメントで宣言する必要があります。
element
のデータ型を明示的に宣言するには、As
句を使用します。 要素のデータ型が For Each
...Next
コンストラクトの外部で定義されていない限り、そのスコープはループの本体です。 ループの外側と内部の両方 element
宣言できないことに注意してください。
必要に応じて、Next
ステートメントでelement
を指定できます。 これにより、特に入れ子になった For Each
ループがある場合に、プログラムの読みやすさが向上します。 対応する For Each
ステートメントに表示される変数と同じ変数を指定する必要があります。
ループ内で element
の値を変更しないようにすることができます。 これを行うと、コードの読み取りとデバッグがより困難になる可能性があります。
group
の値を変更しても、ループが最初に入力されたときに決定されたコレクションまたはその要素には影響しません。
ループを入れ子にすると、外側の入れ子レベルの Next
ステートメントが内部レベルの Next
の前に検出された場合、コンパイラはエラーを通知します。 ただし、コンパイラは、すべてのelement
ステートメントでNext
を指定した場合にのみ、この重複するエラーを検出できます。
コードが特定の順序でコレクションを走査することに依存している場合、コレクションが公開する列挙子オブジェクトの特性がわかっている場合を除き、 For Each
...Next
ループは最適な選択ではありません。 トラバーサルの順序は Visual Basic ではなく、列挙子オブジェクトの MoveNext メソッドによって決まります。 そのため、コレクションのどの要素が最初に element
で返されるか、または指定された要素の後に返される次の要素であるかを予測できない場合があります。
For
...Next
やDo
...Loop
など、別のループ構造を使用すると、より信頼性の高い結果が得られます。
ランタイムは、 group
内の要素を element
に変換できる必要があります。 [Option Strict
] ステートメントは、拡大変換と縮小変換の両方を許可するか (Option Strict
はオフ、既定値)、拡大変換のみを許可するか (Option Strict
はオン) を制御します。 詳細については、「 縮小変換」を参照してください。
group
のデータ型は、列挙可能なコレクションまたは配列を参照する参照型である必要があります。 最も一般的には、group
は、System.Collections
名前空間のIEnumerable インターフェイスまたはSystem.Collections.Generic
名前空間のIEnumerable<T> インターフェイスを実装するオブジェクトを参照します。
System.Collections.IEnumerable
は、コレクションの列挙子オブジェクトを返す GetEnumerator メソッドを定義します。 列挙子オブジェクトは、System.Collections
名前空間のSystem.Collections.IEnumerator
インターフェイスを実装し、Current プロパティとResetメソッドとMoveNext メソッドを公開します。 Visual Basic では、これらを使用してコレクションを走査します。
縮小変換
Option Strict
を On
に設定すると、通常、縮小変換によってコンパイラ エラーが発生します。 ただし、 For Each
ステートメントでは、 group
内の要素から element
への変換は実行時に評価および実行され、縮小変換によって発生するコンパイラ エラーは抑制されます。
次の例では、Long
からInteger
への変換は縮小変換であるため、n
の初期値としてのm
の割り当ては、Option Strict
がオンのときにコンパイルされません。 ただし、 For Each
ステートメントでは、 number
への割り当てに Long
から Integer
への同じ変換が必要であっても、コンパイラ エラーは報告されません。 大きな数を含む For Each
ステートメントでは、 ToInteger が大きな数値に適用されると実行時エラーが発生します。
Option Strict On
Imports System
Module Program
Sub Main(args As String())
' 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, even when Option Strict is on.
For Each number As Integer In New Long() {45, 3, 987}
Console.Write(number & " ")
Next
Console.WriteLine()
' Output: 45 3 987
' Here a run-time error is raised because 9876543210
' is too large for type Integer.
'For Each number As Integer In New Long() {45, 3, 9876543210}
' Console.Write(number & " ")
'Next
End Sub
End Module
IEnumerator の呼び出し
For Each
...Next
ループの実行が開始されると、group
が有効なコレクション オブジェクトを参照していることを確認します。 そうでない場合は、例外がスローされます。 それ以外の場合は、 MoveNext メソッドと列挙子オブジェクトの Current プロパティを呼び出して、最初の要素を返します。
MoveNext
が次の要素がないことを示す場合、つまりコレクションが空の場合、For Each
ループは停止し、Next
ステートメントの後のステートメントに制御が渡されます。 それ以外の場合、Visual Basic は最初の要素に element
を設定し、ステートメント ブロックを実行します。
Visual Basic は、 Next
ステートメントを検出するたびに、 For Each
ステートメントに戻ります。 ここでも、 MoveNext
と Current
を呼び出して次の要素を返し、もう一度ブロックを実行するか、結果に応じてループを停止します。 このプロセスは、 MoveNext
が次の要素がないことを示すか、 Exit For
ステートメントが見つかるまで続行されます。
コレクションの変更。 通常、 GetEnumerator によって返される列挙子オブジェクトでは、要素の追加、削除、置換、または並べ替えによってコレクションを変更することはできません。
For Each
...Next
ループを開始した後でコレクションを変更すると、列挙子オブジェクトが無効になり、次に要素にアクセスしようとするとInvalidOperationException例外が発生します。
ただし、この変更のブロックは Visual Basic ではなく、 IEnumerable インターフェイスの実装によって決まります。 反復中に変更を可能にする方法で IEnumerable
を実装することができます。 このような動的な変更を行うことを検討している場合は、使用しているコレクションに対する IEnumerable
実装の特性を理解していることを確認してください。
コレクション要素の変更。 列挙子オブジェクトの Current プロパティは ReadOnly であり、各コレクション要素のローカル コピーを返します。 つまり、 For Each
...Next
ループ内の要素自体を変更することはできません。 行った変更は、 Current
からのローカル コピーにのみ影響し、基になるコレクションには反映されません。 ただし、要素が参照型の場合は、その要素が指すインスタンスのメンバーを変更できます。 次の例では、各thisControl
要素のBackColor
メンバーを変更します。 ただし、 thisControl
自体を変更することはできません。
Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
For Each thisControl In thisForm.Controls
thisControl.BackColor = System.Drawing.Color.LightBlue
Next thisControl
End Sub
前の例では、各thisControl
要素のBackColor
メンバーを変更できますが、thisControl
自体は変更できません。
配列の走査。
Array クラスはIEnumerable インターフェイスを実装するため、すべての配列でGetEnumerator メソッドが公開されます。 つまり、 For Each
...Next
ループを使用して配列を反復処理できます。 ただし、読み取ることができるのは配列要素のみです。 変更することはできません。
例 1
次の例では、 DirectoryInfo クラスを使用して、C:\ ディレクトリ内のすべてのフォルダーを一覧表示します。
Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
Debug.WriteLine(dir.Name)
Next
例 2
次の例は、コレクションを並べ替える手順を示しています。 この例では、List<T>に格納されているCar
クラスのインスタンスを並べ替えます。
Car
クラスは、IComparable<T> インターフェイスを実装します。そのためには、CompareTo メソッドを実装する必要があります。
CompareTo メソッドを呼び出すたびに、並べ替えに使用される 1 つの比較が行われます。
CompareTo
メソッドのユーザー記述コードは、現在のオブジェクトと別のオブジェクトの比較ごとに値を返します。 現在のオブジェクトが他のオブジェクトより小さい場合、返される値は 0 未満、現在のオブジェクトが他のオブジェクトより大きい場合は 0 より大きく、等しい場合は 0 になります。 これにより、より大きい、より小さい、等しいという条件をコードで定義できます。
ListCars
メソッドでは、cars.Sort()
ステートメントによってリストが並べ替えられます。 このSortのList<T> メソッドを呼び出すと、CompareTo
内のCar
オブジェクトに対してList
メソッドが自動的に呼び出されます。
Public Sub ListCars()
' Create some new cars.
Dim cars As New List(Of Car) From
{
New Car With {.Name = "car1", .Color = "blue", .Speed = 20},
New Car With {.Name = "car2", .Color = "red", .Speed = 50},
New Car With {.Name = "car3", .Color = "green", .Speed = 10},
New Car With {.Name = "car4", .Color = "blue", .Speed = 50},
New Car With {.Name = "car5", .Color = "blue", .Speed = 30},
New Car With {.Name = "car6", .Color = "red", .Speed = 60},
New Car With {.Name = "car7", .Color = "green", .Speed = 50}
}
' Sort the cars by color alphabetically, and then by speed
' in descending order.
cars.Sort()
' View all of the cars.
For Each thisCar As Car In cars
Debug.Write(thisCar.Color.PadRight(5) & " ")
Debug.Write(thisCar.Speed.ToString & " ")
Debug.Write(thisCar.Name)
Debug.WriteLine("")
Next
' Output:
' blue 50 car4
' blue 30 car5
' blue 20 car1
' green 50 car7
' green 10 car3
' red 60 car6
' red 50 car2
End Sub
Public Class Car
Implements IComparable(Of Car)
Public Property Name As String
Public Property Speed As Integer
Public Property Color As String
Public Function CompareTo(ByVal other As Car) As Integer _
Implements System.IComparable(Of Car).CompareTo
' A call to this method makes a single comparison that is
' used for sorting.
' Determine the relative order of the objects being compared.
' Sort by color alphabetically, and then by speed in
' descending order.
' Compare the colors.
Dim compare As Integer
compare = String.Compare(Me.Color, other.Color, True)
' If the colors are the same, compare the speeds.
If compare = 0 Then
compare = Me.Speed.CompareTo(other.Speed)
' Use descending order for speed.
compare = -compare
End If
Return compare
End Function
End Class
こちらも参照ください
.NET