Pernyataan For...Next (Visual Basic)

Mengulangi sekelompok pernyataan untuk setiap elemen dalam koleksi.

Sintaks

For Each element [ As datatype ] In group
    [ statements ]
    [ Continue For ]
    [ statements ]
    [ Exit For ]
    [ statements ]
Next [ element ]

Generator

Term Definisi
element Diperlukan dalam pernyataan For Each. Opsional dalam pernyataan Next. Variable. Yang digunakan untuk mengulang seluruh elemen koleksi.
datatype Opsional jika Option Infer aktif (default) atau element sudah dinyatakan; wajib diisi jika Option Infer nonaktif dan element belum dinyatakan. Jenis data element.
group Harus diisi. Variabel dengan jenis yang merupakan jenis koleksi atau Objek. Mengacu pada koleksi tempat statements akan diulang.
statements Opsional. Satu atau lebih pernyataan di antara For Each dan Next yang berjalan pada setiap item di group.
Continue For Opsional. Mentransfer kontrol ke awal pengulangan For Each.
Exit For Opsional. Mentransfer kontrol keluar dari perulangan For Each.
Next Harus diisi. Mengakhiri definisi perulangan For Each.

Contoh sederhana

Gunakan pengulangan For Each...Next saat Anda ingin mengulangi sekumpulan pernyataan untuk setiap elemen koleksi atau array.

Tip

Pernyataan For...Next berfungsi dengan baik ketika Anda dapat mengaitkan setiap iterasi pengulangan dengan satu variabel kontrol dan menentukan nilai awal dan akhir variabel tersebut. Namun, ketika Anda menangani koleksi, konsep nilai awal dan akhir tidak bermakna, dan Anda tidak selalu tahu berapa banyak elemen yang ada dalam koleksi tersebut. Dalam kasus seperti ini, pengulangan For Each...Next sering menjadi pilihan yang lebih baik.

Dalam contoh berikut, For Each…Pernyataan Next berulang di seluruh elemen koleksi Daftar.

' 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

Untuk contoh selengkapnya, lihat Koleksi dan Array.

Pengulangan berlapis

Anda dapat menyarangkan perulangan For Each dengan menempatkan satu perulangan di dalam perulangan lainnya.

Contoh berikut menunjukkan For Each berlapis...Struktur 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

Saat Anda menyarangkan pengulangan, setiap pengulangan harus memiliki variabel element yang unik.

Anda juga dapat menyusun berbagai jenis struktur kontrol di dalam satu sama lain. Untuk informasi selengkapnya, lihat Struktur Kontrol Berlapis.

Keluar Untuk dan Lanjutkan Untuk

Pernyataan Exit For menyebabkan eksekusi keluar dari For...Loop Next dan transfer mengontrol ke pernyataan yang mengikuti pernyataan Next.

Pernyataan Continue For mentransfer kontrol segera ke iterasi perulangan berikutnya. Untuk informasi selengkapnya, lihat Pernyataan Continue.

Contoh berikut menunjukkan cara menggunakan pernyataan Continue For dan 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

Anda dapat menempatkan sejumlah pernyataan Exit For dalam pengulanan For Each… Saat digunakan dalam perulangan For Each berlapis, Exit For menyebabkan eksekusi mengeluarkan pengulangan terdalam dan mentransfer kontrol ke tingkat pelapisan berikutnya yang lebih tinggi.

Exit For sering digunakan setelah kondisi evaluasi kondisi tertentu, misalnya dalam struktur If...Then...Else. Anda mungkin ingin menggunakan Exit For untuk kondisi berikut:

  • Melanjutkan iterasi tidak perlu atau tidak mungkin. Ini mungkin disebabkan oleh nilai yang salah atau permintaan penghentian.

  • Pengecualian tertangkap dalam Try...Catch...Finally. Anda dapat menggunakan Exit For di akhir blok Finally.

  • Ada pengulangan tanpa akhir, yang merupakan pengulangan yang dapat menjalankan dalam jumlah banyak kali atau bahkan tak terbatas. Jika Anda mendeteksi kondisi seperti itu, Anda dapat menggunakan Exit For untuk keluar dari pengulangan itu. Untuk informasi selengkapnya, lihat Pernyataan Do...Loop.

Iterator

Anda menggunakan iterator untuk melakukan iterasi kustom pada satu koleksi. Iterator dapat menjadi fungsi atau aksesor Get. Iterator menggunakan pernyataan Yield untuk mengembalikan setiap elemen koleksi satu per satu.

Anda memanggil iterator dengan pernyataan For Each...Next. Setiap perulangan dari perulangan For Each akan memanggil pengulang. Ketika pernyataan Yield tercapai di iterator, ekspresi dalam pernyataan Yield dikembalikan, dan lokasi saat ini dalam kode dipertahankan. Eksekusi dimulai ulang dari lokasi tersebut saat iterator dipanggil lain kali.

Contoh berikut menggunakan fungsi iterator. Fungsi iterator memiliki pernyataan Yield yang ada di dalam pengulangan For...Next. Dalam metode ListEvenNumbers, setiap iterasi isi pernyataan For Each membuat panggilan ke fungsi iterator, yang berlanjut ke pernyataan Yield berikutnya.

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

Untuk informasi selengkapnya, lihat Iterator, Pernyataan Yield, dan Iterator.

Implementasi teknis

Ketika For Each...Pernyataan Next berjalan, Visual Basic mengevaluasi koleksi hanya satu kali, sebelum pengulangan tersebut dimulai. Jika blok pernyataan Anda mengubah element atau group, perubahan ini tidak memengaruhi iterasi pengulangan.

Ketika semua elemen dalam koleksi telah berturut-turut ditetapkan ke element, pengulangan For Each berhenti dan kontrol meneruskan ke pernyataan setelah pernyataan Next.

Jika Opsi Infer aktif (pengaturan defaultnya), kompiler Visual Basic dapat menyimpulkan jenis data element. Jika tidak aktif dan element belum dinyatakan di luar pengulangan, Anda harus menyatakannya dalam pernyataan For Each. Untuk mendeklarasikan jenis data element secara eksplisit, gunakan klausa As. Kecuali jenis data elemen didefinisikan di luar konstruksi For Each...Next, cakupannya adalah isi pengulangan. Perhatikan bahwa Anda tidak dapat mendeklarasikan element baik di luar maupun di dalam pengulangan.

Anda dapat secara opsional menentukan element dalam pernyataan Next. Ini meningkatkan keterbacaan program Anda, terutama jika Anda memiliki pengulangan berlapis For Each. Anda harus menentukan variabel yang sama dengan variabel yang muncul dalam pernyataan For Each yang sesuai.

Anda mungkin ingin menghindari perubahan nilai element di dalam pengulangan. Melakukan ini dapat membuatnya lebih sulit untuk membaca dan men-debug kode Anda. Mengubah nilai group tidak memengaruhi koleksi atau elemennya, yang ditentukan ketika pengulangan pertama kali dimasukkan.

Saat Anda menyarangkan pengulangan, jika pernyataan Next tingkat pelapisan luar ditemukan sebelum Next tingkat dalam, kompiler akan memberi sinyal kesalahan. Namun, kompiler dapat mendeteksi kesalahan yang tumpang tindih ini hanya jika Anda menentukan element dalam setiap pernyataan Next.

Jika kode Anda tergantung pada pelintasan koleksi dalam urutan tertentu, pengulangan For Each...Next bukanlah pilihan terbaik, kecuali Anda tahu karakteristik objek enumerator yang diekspos koleksi tersebut. Urutan perlintasan tidak ditentukan oleh Visual Basic, tetapi dengan metode MoveNext dari objek enumerator. Oleh karena itu, Anda mungkin tidak dapat memprediksi elemen koleksi mana yang pertama kali dikembalikan dalam element, atau mana elemen berikutnya yang dikembalikan setelah elemen tertentu. Anda mungkin mencapai hasil yang lebih andal menggunakan struktur pengulangan yang berbeda, seperti For...Next atau Do...Loop.

Runtime harus dapat mengonversi elemen dalam group ke element. Pernyataan [Option Strict] mengontrol apakah konversi pelebaran dan penyempitan diizinkan (Option Strict nonaktif, nilai defaultnya), atau apakah hanya konversi pelebaran yang diizinkan (Option Strict aktif). Untuk informasi selengkapnya, lihat Konversi Penyempitan.

Jenis data group harus berupa jenis referensi yang mengacu pada koleksi atau array yang dapat dienumerasi. Paling umum artinya bahwa group mengacu pada objek yang mengimplementasikan antarmuka IEnumerable dari namespace layanan System.Collections atau antarmuka IEnumerable<T> dari namespace System.Collections.Generic. System.Collections.IEnumerable mendefinisikan metode GetEnumerator, yang mengembalikan objek enumerator untuk koleksi itu. Objek enumerator mengimplementasikan antarmuka System.Collections.IEnumerator dari namespace layanan System.Collections dan mengekspos properti Current dan metode Reset dan MoveNext. Visual Basic menggunakan ini untuk melintasi koleksi.

Mempersempit Konversi

Ketika Option Strict diatur ke On, mempersempit konversi biasanya menyebabkan kesalahan kompiler. Namun, dalam pernyataan For Each, konversi dari elemen dalam group ke element dievaluasi dan dilakukan pada durasi, dan kesalahan kompiler yang disebabkan oleh konversi penyempitan ditekan.

Dalam contoh berikut, penetapan m sebagai nilai awal untuk n tidak mengkompilasi ketika Option Strict aktif karena konversi Long ke Integer adalah konversi penyempitan. Namun, dalam pernyataan For Each, tidak ada kesalahan kompiler yang dilaporkan, meskipun penugasan untuk number memerlukan konversi yang sama dari Long ke Integer. Dalam pernyataan For Each yang berisi angka besar, kesalahan run-time terjadi ketika ToInteger diterapkan ke jumlah yang besar itu.

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

Panggilan IEnumerator

Ketika eksekusi pengulangan For Each...Next dimulai, Visual Basic memverifikasi bahwa group merujuk pada objek koleksi yang valid. Jika tidak, Visual Basic akan melemparkan pengecualian. Jika tidak, ia memanggil metode MoveNext dan properti Current objek enumerator untuk mengembalikan elemen pertama. Jika MoveNext menunjukkan bahwa tidak ada elemen berikutnya, yaitu, jika koleksi kosong, pengulangan For Each berhenti dan kontrol meneruskan ke pernyataan setelah pernyataan Next. Jika tidak, Visual Basic menetapkan element ke elemen pertama dan menjalankan blok pernyataan.

Setiap kali Visual Basic menemukan pernyataan Next, pernyataan tersebut kembali ke pernyataan For Each. Sekali lagi ia memanggil MoveNext dan Current untuk mengembalikan elemen berikutnya, dan sekali lagi menjalankan blok atau menghentikan pengulangan tergantung pada hasilnya. Proses ini berlanjut sampai MoveNext menunjukkan bahwa tidak ada elemen berikutnya atau pernyataan Exit For yang ditemui.

Memodifikasi Koleksi. Objek enumerator yang dikembalikan oleh GetEnumerator biasanya tidak memungkinkan Anda mengubah koleksi dengan menambahkan, menghapus, mengganti, atau menyusun ulang elemen apa pun. Jika Anda mengubah koleksi setelah memulai pengulangan For Each...Next, objek enumerator menjadi tidak valid, dan upaya berikutnya untuk mengakses elemen menyebabkan perkecualian InvalidOperationException.

Namun, pemblokiran modifikasi ini tidak ditentukan oleh Visual Basic, melainkan oleh implementasi antarmuka IEnumerable. Menerapkan IEnumerable bisa dengan cara yang memungkinkan modifikasi selama iterasi. Jika Anda mempertimbangkan untuk melakukan modifikasi dinamis seperti itu, pastikan Anda memahami karakteristik implementasi IEnumerable pada koleksi yang Anda gunakan.

Memodifikasi Elemen Koleksi. Properti Current objek enumerator adalah ReadOnly, dan mengembalikan salinan lokal dari setiap elemen koleksi. Artinya Anda tidak dapat memodifikasi elemen itu sendiri dalam pengulangan For Each...Next. Setiap modifikasi yang Anda buat hanya memengaruhi salinan lokal dari Current dan tidak tercermin kembali ke dalam koleksi yang mendasar. Namun, jika elemen adalah jenis referensi, Anda dapat memodifikasi anggota instans yang dituju. Contoh berikut memodifikasi anggota BackColor dari setiap elemen thisControl. Namun, Anda tidak dapat memodifikasi thisControl itu sendiri.

Sub LightBlueBackground(thisForm As System.Windows.Forms.Form)
    For Each thisControl In thisForm.Controls
        thisControl.BackColor = System.Drawing.Color.LightBlue
    Next thisControl
End Sub

Contoh sebelumnya dapat memodifikasi anggota BackColor setiap elemen thisControl, meskipun tidak dapat memodifikasi thisControl itu sendiri.

Melintas Array. Karena kelas Array mengimplementasikan antarmuka IEnumerable, semua array mengekspos metode GetEnumerator. Ini berarti bahwa Anda dapat melakukan iterasi melalui array dengan pengulangan For Each...Next. Namun, Anda hanya dapat membaca elemen array. Anda tidak bisa mengubahnya.

Contoh 1

Contoh berikut mencantumkan semua folder di C:\ direktori dengan menggunakan kelas DirectoryInfo.

Dim dInfo As New System.IO.DirectoryInfo("c:\")
For Each dir As System.IO.DirectoryInfo In dInfo.GetDirectories()
    Debug.WriteLine(dir.Name)
Next

Contoh 2

Contoh berikut mengilustrasikan prosedur untuk mengurutkan koleksi. Contoh tersebut mengurutkan instans kelas Car yang disimpan dalam List<T>. Kelas Car menerapkan antarmuka IComparable<T>, yang mengharuskan metode CompareTo untuk diterapkan.

Setiap panggilan ke metode CompareTo membuat perbandingan tunggal yang digunakan untuk pengurutan. Kode yang ditulis pengguna dalam metode CompareTo mengembalikan nilai untuk setiap perbandingan objek saat ini dengan objek lain. Nilai yang ditampilkan menjadi kurang dari nol jika objek saat ini kurang dari objek lainnya, menjadi lebih dari nol jika objek saat ini lebih besar dari objek lainnya, dan menjadi nol jika besarnya sama. Ini memungkinkan Anda untuk menentukan dalam kode kriteria yang lebih dari, kurang dari, dan sama dengan.

Dalam metode ListCars, pernyataan cars.Sort() mengurutkan daftar. Panggilan ini ke metode Sort dari List<T> menyebabkan metode CompareTo dipanggil secara otomatis untuk objek Car di 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

Lihat juga