Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Pernyataan mewakili kode yang dapat dieksekusi.
Statement
: LabelDeclarationStatement
| LocalDeclarationStatement
| WithStatement
| SyncLockStatement
| EventStatement
| AssignmentStatement
| InvocationStatement
| ConditionalStatement
| LoopStatement
| ErrorHandlingStatement
| BranchStatement
| ArrayHandlingStatement
| UsingStatement
| AwaitStatement
| YieldStatement
;
Nota. Microsoft Visual Basic Compiler hanya mengizinkan pernyataan yang dimulai dengan kata kunci atau pengidentifikasi. Jadi, misalnya, pernyataan pemanggilan "Call (Console).WriteLine" diizinkan, tetapi pernyataan pemanggilan "(Console).WriteLine" tidak.
Alur Kontrol
Alur kontrol adalah urutan di mana pernyataan dan ekspresi dijalankan. Urutan eksekusi tergantung pada pernyataan atau ekspresi tertentu.
Misalnya, saat mengevaluasi operator penambahan ( Operator Penambahan Bagian), pertama operand kiri dievaluasi, lalu operand kanan, lalu operator itu sendiri. Blok dijalankan ( Blok Bagian dan Label) dengan terlebih dahulu menjalankan substatement pertamanya, lalu melanjutkan satu per satu melalui pernyataan blok.
Implisit dalam urutan ini adalah konsep titik kontrol, yang merupakan operasi berikutnya yang akan dijalankan. Ketika metode dipanggil (atau "dipanggil"), kami mengatakan metode tersebut membuat instans metode . Instans metode terdiri dari salinan parameter metode dan variabel lokalnya sendiri, dan titik kontrolnya sendiri.
Metode Reguler
Berikut adalah contoh metode reguler
Function Test() As Integer
Console.WriteLine("hello")
Return 1
End Function
Dim x = Test() ' invokes the function, prints "hello", assigns 1 to x
Ketika metode reguler dipanggil,
- Pertama, instans metode dibuat khusus untuk pemanggilan tersebut. Instans ini mencakup salinan semua parameter dan variabel lokal metode .
- Kemudian semua parameternya diinisialisasi ke nilai yang disediakan, dan semua variabel lokalnya ke nilai default jenisnya.
- Dalam kasus
Function, variabel lokal implisit juga diinisialisasi yang disebut variabel pengembalian fungsi yang namanya adalah nama fungsi, yang jenisnya adalah jenis pengembalian fungsi dan yang nilai awalnya adalah default dari jenisnya. - Titik kontrol instans metode kemudian diatur pada pernyataan pertama isi metode, dan isi metode segera mulai dijalankan dari sana ( Blok Bagian dan Label).
Ketika alur kontrol keluar dari isi metode secara normal - melalui mencapai End Function atau End Sub yang menandai akhirnya, atau melalui eksplisit Return atau Exit pernyataan - alur kontrol kembali ke pemanggil instans metode. Jika ada variabel pengembalian fungsi, hasil pemanggilan adalah nilai akhir variabel ini.
Ketika alur kontrol keluar dari isi metode melalui pengecualian yang tidak tertangani, pengecualian tersebut disebarkan ke pemanggil.
Setelah alur kontrol keluar, tidak ada lagi referensi langsung ke instans metode. Jika instans metode menyimpan satu-satunya referensi ke salinan variabel atau parameter lokalnya, maka mungkin sampah dikumpulkan.
Metode Iterator
Metode iterator digunakan sebagai cara yang mudah untuk menghasilkan urutan, yang dapat dikonsumsi oleh For Each pernyataan. Metode iterator menggunakan Yield pernyataan ( Pernyataan Hasil Bagian) untuk memberikan elemen urutan. (Metode iterator tanpa Yield pernyataan akan menghasilkan urutan kosong). Berikut adalah contoh metode iterator:
Iterator Function Test() As IEnumerable(Of Integer)
Console.WriteLine("hello")
Yield 1
Yield 2
End Function
Dim en = Test()
For Each x In en ' prints "hello" before the first x
Console.WriteLine(x) ' prints "1" and then "2"
Next
Ketika metode iterator dipanggil yang jenis pengembaliannya adalah IEnumerator(Of T),
- Pertama, instans metode iterator dibuat khusus untuk pemanggilan tersebut. Instans ini mencakup salinan semua parameter dan variabel lokal metode .
- Kemudian semua parameternya diinisialisasi ke nilai yang disediakan, dan semua variabel lokalnya ke nilai default jenisnya.
- Variabel lokal implisit juga diinisialisasi yang disebut variabel iterator saat ini, yang jenisnya adalah
Tdan yang nilai awalnya adalah default dari jenisnya. - Titik kontrol instans metode kemudian diatur pada pernyataan pertama isi metode.
- Objek iterator kemudian dibuat, terkait dengan instans metode ini. Objek iterator mengimplementasikan jenis pengembalian yang dinyatakan dan memiliki perilaku seperti yang dijelaskan di bawah ini.
- Alur kontrol kemudian dilanjutkan segera di pemanggil, dan hasil pemanggilan adalah objek iterator. Perhatikan bahwa transfer ini dilakukan tanpa keluar dari instans metode iterator, dan tidak menyebabkan penangan akhirnya dijalankan. Instans metode masih direferensikan oleh objek iterator, dan tidak akan menjadi sampah yang dikumpulkan selama ada referensi langsung ke objek iterator.
Ketika properti objek Current iterator diakses, variabel saat ini dari pemanggilan dikembalikan.
Ketika metode objek MoveNext iterator dipanggil, pemanggilan tidak membuat instans metode baru. Sebagai gantinya, instans metode yang ada digunakan (dan titik kontrol dan variabel dan parameter lokalnya) - instans yang dibuat saat metode iterator pertama kali dipanggil. Alur kontrol melanjutkan eksekusi pada titik kontrol instans metode tersebut, dan melanjutkan melalui isi metode iterator seperti biasa.
Ketika metode objek Dispose iterator dipanggil, sekali lagi instans metode yang ada digunakan. Alur kontrol dilanjutkan pada titik kontrol instans metode tersebut, tetapi kemudian segera berperilaku seolah-olah Exit Function pernyataan adalah operasi berikutnya.
Deskripsi perilaku di atas untuk pemanggilan MoveNext atau Dispose pada objek iterator hanya berlaku jika semua pemanggilan sebelumnya atau MoveNextDispose pada objek iterator tersebut telah dikembalikan ke pemanggil mereka. Jika belum, maka perilakunya tidak ditentukan.
Ketika alur kontrol keluar dari isi metode iterator biasanya -- melalui mencapai End Function tanda itu ujungnya, atau melalui eksplisit Return atau Exit pernyataan -- itu harus dilakukan dalam konteks pemanggilan MoveNext atau Dispose fungsi pada objek iterator untuk melanjutkan instans metode iterator, dan itu akan menggunakan instans metode yang dibuat ketika metode iterator pertama kali dipanggil. Titik kontrol instans tersebut End Function dibiarkan pada pernyataan, dan alur kontrol dilanjutkan di pemanggil; dan jika telah dilanjutkan oleh panggilan ke MoveNext maka nilai False dikembalikan ke pemanggil.
Ketika aliran kontrol keluar dari isi metode iterator melalui pengecualian yang tidak tertangani, maka pengecualian disebarkan ke pemanggil, yang sekali lagi akan menjadi pemanggilan MoveNext atau dari Dispose.
Adapun kemungkinan lainnya mengembalikan jenis fungsi iterator,
- Ketika metode iterator dipanggil yang jenis pengembaliannya adalah
IEnumerable(Of T)untuk beberapaT, instans pertama kali dibuat -- khusus untuk pemanggilan metode iterator -- dari semua parameter dalam metode, dan diinisialisasi dengan nilai yang disediakan. Hasil pemanggilan adalah objek yang mengimplementasikan jenis pengembalian. Jika metode objekGetEnumeratorini dipanggil, metode ini membuat instans -- khusus untuk pemanggilanGetEnumerator-- dari semua parameter dan variabel lokal dalam metode . Ini menginisialisasi parameter ke nilai yang sudah disimpan, dan melanjutkan seperti metode iterator di atas. - Ketika metode iterator dipanggil yang jenis pengembaliannya adalah antarmuka
IEnumeratornon-generik , perilakunya persis seperti untukIEnumerator(Of Object). - Ketika metode iterator dipanggil yang jenis pengembaliannya adalah antarmuka
IEnumerablenon-generik , perilakunya persis seperti untukIEnumerable(Of Object).
Metode Asinkron
Metode asinkron adalah cara mudah untuk melakukan pekerjaan jangka panjang tanpa misalnya memblokir UI aplikasi. Asinkron adalah kependekan dari Asinkron - itu berarti bahwa pemanggil metode asinkron akan segera melanjutkan eksekusinya, tetapi akhirnya penyelesaian instans metode asinkron dapat terjadi di lain waktu di masa depan. Dengan metode asinkron konvensi dinamai dengan akhiran "Asinkron".
Async Function TestAsync() As Task(Of String)
Console.WriteLine("hello")
Await Task.Delay(100)
Return "world"
End Function
Dim t = TestAsync() ' prints "hello"
Console.WriteLine(Await t) ' prints "world"
Nota. Metode asinkron tidak dijalankan pada utas latar belakang. Sebaliknya mereka mengizinkan metode untuk menangguhkan dirinya sendiri melalui Await operator, dan menjadwalkan dirinya untuk dilanjutkan sebagai respons terhadap beberapa peristiwa.
Ketika metode asinkron dipanggil
- Pertama, instans metode asinkron dibuat khusus untuk pemanggilan tersebut. Instans ini mencakup salinan semua parameter dan variabel lokal metode .
- Kemudian semua parameternya diinisialisasi ke nilai yang disediakan, dan semua variabel lokalnya ke nilai default jenisnya.
- Dalam kasus metode asinkron dengan jenis
Task(Of T)pengembalian untuk beberapaT, variabel lokal implisit juga diinisialisasi yang disebut variabel pengembalian tugas, yang jenisnya adalahTdan yang nilai awalnya adalah default .T - Jika metode asinkron adalah
Functiondengan jenisTaskpengembalian atauTask(Of T)untuk beberapaT, maka objek dari jenis tersebut dibuat secara implisit, yang terkait dengan pemanggilan saat ini. Ini disebut objek asinkron dan mewakili pekerjaan di masa depan yang akan dilakukan dengan menjalankan instans metode asinkron. Ketika kontrol dilanjutkan dalam pemanggil instans metode asinkron ini, pemanggil akan menerima objek asinkron ini sebagai hasil pemanggilannya. - Titik kontrol instans kemudian diatur pada pernyataan pertama isi metode asinkron, dan segera mulai menjalankan isi metode dari sana ( Blok Bagian dan Label).
Delegasi Resumption dan Pemanggil Saat Ini
Sebagaimana dirinci dalam Bagian Menunggu Operator, eksekusi Await ekspresi memiliki kemampuan untuk menangguhkan titik kontrol instans metode yang meninggalkan alur kontrol untuk pergi ke tempat lain. Alur kontrol nantinya dapat dilanjutkan pada titik kontrol instans yang sama melalui pemanggilan delegasi penerbitan ulang. Perhatikan bahwa penangguhan ini dilakukan tanpa keluar dari metode asinkron, dan tidak menyebabkan penangan akhirnya dijalankan. Instans metode masih direferensikan oleh delegasi penerbitan ulang dan Task hasil atau Task(Of T) (jika ada), dan tidak akan dikumpulkan selama ada referensi langsung untuk delegasi atau hasil.
Sangat membantu untuk membayangkan pernyataan Dim x = Await WorkAsync() itu kira-kira sebagai singkatan sintik untuk hal-hal berikut:
Dim temp = WorkAsync().GetAwaiter()
If Not temp.IsCompleted Then
temp.OnCompleted(resumptionDelegate)
Return [task]
CONT: ' invocation of 'resumptionDelegate' will resume here
End If
Dim x = temp.GetResult()
Dalam hal berikut, pemanggil instans metode saat ini didefinisikan sebagai pemanggil asli, atau pemanggil delegasi penerbitan ulang, mana yang lebih baru.
Ketika alur kontrol keluar dari isi metode asinkron -- melalui mencapai End Sub atau End Function yang menandai akhirnya, atau melalui eksplisit Return atau Exit pernyataan, atau melalui pengecualian yang tidak tertangani -- titik kontrol instans diatur ke akhir metode. Perilaku kemudian tergantung pada jenis pengembalian metode asinkron.
Dalam kasus
Async Functiondengan jenisTaskpengembalian :Jika alur kontrol keluar melalui pengecualian yang tidak tertangani, maka status objek asinkron diatur ke
TaskStatus.Faulteddan propertinyaException.InnerExceptiondiatur ke pengecualian (kecuali: pengecualian tertentu yang ditentukan implementasi sepertiOperationCanceledExceptionmengubahnya menjadiTaskStatus.Canceled). Alur kontrol dilanjutkan di pemanggil saat ini.Jika tidak, status objek asinkron diatur ke
TaskStatus.Completed. Alur kontrol dilanjutkan di pemanggil saat ini.(Catatan. Seluruh titik Tugas, dan apa yang membuat metode asinkron menarik, adalah bahwa ketika tugas selesai maka metode apa pun yang menunggunya saat ini akan mengeksekusi delegasi asinkron mereka, yaitu mereka akan menjadi tidak diblokir.)
Dalam kasus
Async Functiondengan jenisTask(Of T)pengembalian untuk beberapaT: perilakunya seperti di atas, kecuali bahwa dalam kasus non-pengecualian properti objekResultasinkron juga diatur ke nilai akhir variabel pengembalian tugas.Dalam kasus
Async Sub:- Jika alur kontrol keluar melalui pengecualian yang tidak tertangani, maka pengecualian tersebut disebarluaskan ke lingkungan dengan beberapa cara khusus implementasi. Alur kontrol dilanjutkan di pemanggil saat ini.
- Jika tidak, alur kontrol hanya dilanjutkan di pemanggil saat ini.
Sub Asinkron
Ada beberapa perilaku khusus Microsoft dari Async Sub.
Jika SynchronizationContext.Current berada Nothing di awal pemanggilan, maka pengecualian yang tidak tertangani dari Sub Asinkron akan diposting ke Threadpool.
Jika SynchronizationContext.Current tidak Nothing pada awal pemanggilan, maka OperationStarted() dipanggil pada konteks tersebut sebelum dimulainya metode dan OperationCompleted() setelah akhir. Selain itu, setiap pengecualian yang tidak tertangani akan diposting untuk ditumbuhi kembali pada konteks sinkronisasi.
Ini berarti bahwa dalam aplikasi UI, untuk Async Sub yang dipanggil pada utas UI, pengecualian apa pun yang gagal ditangani akan diposting ulang utas UI.
Struktur yang dapat diubah dalam metode asinkron dan iterator
Struktur yang dapat diubah secara umum dianggap praktik buruk, dan tidak didukung oleh metode asinkron atau iterator. Secara khusus, setiap pemanggilan metode asinkron atau iterator dalam struktur akan secara implisit beroperasi pada salinan struktur yang disalin pada saat pemanggilannya. Jadi, misalnya,
Structure S
Dim x As Integer
Async Sub Mutate()
x = 2
End Sub
End Structure
Dim s As New S With {.x = 1}
s.Mutate()
Console.WriteLine(s.x) ' prints "1"
Blok dan Label
Sekelompok pernyataan yang dapat dieksekusi disebut blok pernyataan. Eksekusi blok pernyataan dimulai dengan pernyataan pertama di blok. Setelah pernyataan dijalankan, pernyataan berikutnya dalam urutan leksikal dijalankan, kecuali pernyataan mentransfer eksekusi di tempat lain atau pengecualian terjadi.
Dalam blok pernyataan, pembagian pernyataan pada baris logis tidak signifikan dengan pengecualian pernyataan deklarasi label. Label adalah pengidentifikasi yang mengidentifikasi posisi tertentu dalam blok pernyataan yang dapat digunakan sebagai target pernyataan cabang seperti GoTo.
Block
: Statements*
;
LabelDeclarationStatement
: LabelName ':'
;
LabelName
: Identifier
| IntLiteral
;
Statements
: Statement? ( ':' Statement? )*
;
Pernyataan deklarasi label harus muncul di awal baris logis dan label mungkin berupa pengidentifikasi atau bilangan bulat literal. Karena pernyataan deklarasi label dan pernyataan pemanggilan dapat terdiri dari satu pengidentifikasi, pengidentifikasi tunggal di awal baris lokal selalu dianggap sebagai pernyataan deklarasi label. Pernyataan deklarasi label harus selalu diikuti oleh titik dua, bahkan jika tidak ada pernyataan yang mengikuti pada baris logis yang sama.
Label memiliki ruang deklarasi sendiri dan tidak mengganggu pengidentifikasi lainnya. Contoh berikut valid dan menggunakan variabel x nama baik sebagai parameter maupun sebagai label.
Function F(x As Integer) As Integer
If x >= 0 Then
GoTo x
End If
x = -x
x:
Return x
End Function
Cakupan label adalah isi metode yang berisinya.
Demi keterbacaan, produksi pernyataan yang melibatkan beberapa substatemen diperlakukan sebagai produksi tunggal dalam spesifikasi ini, meskipun substatemen mungkin masing-masing berada di garis berlabel.
Variabel dan Parameter Lokal
Bagian sebelumnya merinci bagaimana dan kapan instans metode dibuat, dan dengannya salinan variabel dan parameter lokal metode. Selain itu, setiap kali isi perulangan dimasukkan, salinan baru dibuat dari setiap variabel lokal yang dideklarasikan di dalam perulangan tersebut seperti yang dijelaskan dalam Pernyataan Perulangan Bagian, dan instans metode sekarang berisi salinan variabel lokalnya daripada salinan sebelumnya.
Semua lokal diinisialisasi ke nilai default jenisnya. Variabel dan parameter lokal selalu dapat diakses publik. Ini adalah kesalahan untuk merujuk ke variabel lokal dalam posisi tekstual yang mendahului deklarasinya, seperti yang diilustrasikan contoh berikut:
Class A
Private i As Integer = 0
Sub F()
i = 1
Dim i As Integer ' Error, use precedes declaration.
i = 2
End Sub
Sub G()
Dim a As Integer = 1
Dim b As Integer = a ' This is valid.
End Sub
End Class
Dalam metode di F atas, penugasan pertama untuk i secara khusus tidak merujuk ke bidang yang dideklarasikan dalam cakupan luar. Sebaliknya, ini mengacu pada variabel lokal, dan kesalahan karena secara tekstual mendahului deklarasi variabel. Dalam metode , G deklarasi variabel berikutnya mengacu pada variabel lokal yang dideklarasikan dalam deklarasi variabel sebelumnya dalam deklarasi variabel lokal yang sama.
Setiap blok dalam metode membuat ruang deklarasi untuk variabel lokal. Nama dimasukkan ke dalam ruang deklarasi ini melalui deklarasi variabel lokal dalam isi metode dan melalui daftar parameter metode , yang memperkenalkan nama ke dalam ruang deklarasi blok terluar. Blok tidak mengizinkan bayangan nama melalui bersarang: setelah nama dideklarasikan dalam blok, nama mungkin tidak dinyatakan ulang di blok berlapis apa pun.
Dengan demikian, dalam contoh berikut, F metode dan G berada dalam kesalahan karena nama i dinyatakan di blok luar dan tidak dapat dinyatakan ulang di blok dalam. Namun, H metode dan I valid karena keduanya idinyatakan dalam blok terpisah yang tidak berlapis.
Class A
Sub F()
Dim i As Integer = 0
If True Then
Dim i As Integer = 1
End If
End Sub
Sub G()
If True Then
Dim i As Integer = 0
End If
Dim i As Integer = 1
End Sub
Sub H()
If True Then
Dim i As Integer = 0
End If
If True Then
Dim i As Integer = 1
End If
End Sub
Sub I()
For i As Integer = 0 To 9
H()
Next i
For i As Integer = 0 To 9
H()
Next i
End Sub
End Class
Ketika metode adalah fungsi, variabel lokal khusus dideklarasikan secara implisit dalam ruang deklarasi isi metode dengan nama yang sama dengan metode yang mewakili nilai pengembalian fungsi. Variabel lokal memiliki semantik resolusi nama khusus saat digunakan dalam ekspresi. Jika variabel lokal digunakan dalam konteks yang mengharapkan ekspresi yang diklasifikasikan sebagai grup metode, seperti ekspresi pemanggilan, maka nama diselesaikan ke fungsi daripada ke variabel lokal. Contohnya:
Function F(i As Integer) As Integer
If i = 0 Then
F = 1 ' Sets the return value.
Else
F = F(i - 1) ' Recursive call.
End If
End Function
Penggunaan tanda kurung dapat menyebabkan situasi ambigu (seperti F(1), di mana F adalah fungsi yang jenis pengembaliannya adalah array satu dimensi); dalam semua situasi ambigu, nama diselesaikan ke fungsi daripada variabel lokal. Contohnya:
Function F(i As Integer) As Integer()
If i = 0 Then
F = new Integer(2) { 1, 2, 3 }
Else
F = F(i - 1) ' Recursive call, not an index.
End If
End Function
Ketika alur kontrol meninggalkan isi metode, nilai variabel lokal diteruskan kembali ke ekspresi pemanggilan. Jika metode adalah subroutine, tidak ada variabel lokal implisit seperti itu, dan kontrol hanya kembali ke ekspresi pemanggilan.
Pernyataan Deklarasi Lokal
Pernyataan deklarasi lokal mendeklarasikan variabel lokal baru, konstanta lokal, atau variabel statis.
Variabel lokal dan konstanta lokal setara dengan variabel instans dan konstanta yang dilingkup ke metode dan dinyatakan dengan cara yang sama.
Variabel statis mirip Shared dengan variabel dan dinyatakan menggunakan pengubah Static .
LocalDeclarationStatement
: LocalModifier VariableDeclarators StatementTerminator
;
LocalModifier
: 'Static' | 'Dim' | 'Const'
;
Variabel statis adalah lokal yang mempertahankan nilainya di seluruh pemanggilan metode. Variabel statis yang dideklarasikan dalam metode non-bersama adalah per instans: setiap instans jenis yang berisi metode memiliki salinan variabel statisnya sendiri. Variabel statis yang dideklarasikan dalam Shared metode adalah per jenis; hanya ada satu salinan variabel statis untuk semua instans. Meskipun variabel lokal diinisialisasi ke nilai default jenisnya pada setiap entri ke dalam metode , variabel statis hanya diinisialisasi ke nilai default jenisnya ketika jenis atau instans jenis diinisialisasi. Variabel statis mungkin tidak dideklarasikan dalam struktur atau metode generik.
Variabel lokal, konstanta lokal, dan variabel statis selalu memiliki aksesibilitas publik dan mungkin tidak menentukan pengubah aksesibilitas. Jika tidak ada jenis yang ditentukan pada pernyataan deklarasi lokal, maka langkah-langkah berikut menentukan jenis deklarasi lokal:
Jika deklarasi memiliki karakter jenis, jenis karakter jenis adalah jenis deklarasi lokal.
Jika deklarasi lokal adalah konstanta lokal, atau jika deklarasi lokal adalah variabel lokal dengan inisialisasi dan inferensi jenis variabel lokal sedang digunakan, jenis deklarasi lokal disimpulkan dari jenis inisialisasi. Jika penginisialisasi mengacu pada deklarasi lokal, kesalahan waktu kompilasi terjadi. (Konstanta lokal diperlukan untuk memiliki penginisialisasi.)
Jika semantik ketat tidak digunakan, jenis pernyataan deklarasi lokal secara
Objectimplisit .Jika tidak, terjadi kesalahan waktu kompilasi.
Jika tidak ada jenis yang ditentukan pada pernyataan deklarasi lokal yang memiliki ukuran array atau pengubah jenis array, maka jenis deklarasi lokal adalah array dengan peringkat yang ditentukan dan langkah-langkah sebelumnya digunakan untuk menentukan jenis elemen array. Jika inferensi jenis variabel lokal digunakan, jenis penginisialisasi harus merupakan jenis array dengan bentuk array yang sama (yaitu pengubah jenis array) sebagai pernyataan deklarasi lokal. Perhatikan bahwa ada kemungkinan bahwa jenis elemen yang disimpulkan mungkin masih merupakan jenis array. Contohnya:
Option Infer On
Module Test
Sub Main()
' Error: initializer is not an array type
Dim x() = 1
' Type is Integer()
Dim y() = New Integer() {}
' Type is Integer()()
Dim z() = New Integer()() {}
' Type is Integer()()()
Dim a()() = New Integer()()() {}
' Error: initializer does not have same array shape
Dim b()() = New Integer(,)() {}
End Sub
End Module
Jika tidak ada jenis yang ditentukan pada pernyataan deklarasi lokal yang memiliki pengubah tipe null, maka jenis deklarasi lokal adalah versi nullable dari jenis yang disimpulkan atau tipe yang disimpulkan itu sendiri jika sudah merupakan jenis nilai nullable. Jika jenis yang disimpulkan bukan jenis nilai yang dapat dibuat nullable, kesalahan waktu kompilasi terjadi. Jika pengubah jenis nullable dan pengubah ukuran array atau jenis array ditempatkan pada pernyataan deklarasi lokal tanpa jenis, maka pengubah jenis null dianggap berlaku untuk jenis elemen array dan langkah-langkah sebelumnya digunakan untuk menentukan jenis elemen.
Penginisialisasi variabel pada pernyataan deklarasi lokal setara dengan pernyataan penugasan yang ditempatkan di lokasi tekstual deklarasi. Dengan demikian, jika cabang eksekusi atas pernyataan deklarasi lokal, penginisialisasi variabel tidak dijalankan. Jika pernyataan deklarasi lokal dijalankan lebih dari sekali, penginisialisasi variabel dijalankan dalam jumlah yang sama. Variabel statis hanya menjalankan penginisialisasi mereka untuk pertama kalinya. Jika pengecualian terjadi saat menginisialisasi variabel statis, variabel statis dianggap diinisialisasi dengan nilai default jenis variabel statis.
Contoh berikut menunjukkan penggunaan penginisialisasi:
Module Test
Sub F()
Static x As Integer = 5
Console.WriteLine("Static variable x = " & x)
x += 1
End Sub
Sub Main()
Dim i As Integer
For i = 1 to 3
F()
Next i
i = 3
label:
Dim y As Integer = 8
If i > 0 Then
Console.WriteLine("Local variable y = " & y)
y -= 1
i -= 1
GoTo label
End If
End Sub
End Module
Program ini mencetak:
Static variable x = 5
Static variable x = 6
Static variable x = 7
Local variable y = 8
Local variable y = 8
Local variable y = 8
Penginisialisasi pada lokal statis aman utas dan terlindungi dari pengecualian selama inisialisasi. Jika pengecualian terjadi selama inisialisasi lokal statis, lokal statis akan memiliki nilai defaultnya dan tidak diinisialisasi. Penginisialisasi lokal statis
Module Test
Sub F()
Static x As Integer = 5
End Sub
End Module
setara dengan:
Imports System.Threading
Imports Microsoft.VisualBasic.CompilerServices
Module Test
Class InitFlag
Public State As Short
End Class
Private xInitFlag As InitFlag = New InitFlag()
Sub F()
Dim x As Integer
If xInitFlag.State <> 1 Then
Monitor.Enter(xInitFlag)
Try
If xInitFlag.State = 0 Then
xInitFlag.State = 2
x = 5
Else If xInitFlag.State = 2 Then
Throw New IncompleteInitialization()
End If
Finally
xInitFlag.State = 1
Monitor.Exit(xInitFlag)
End Try
End If
End Sub
End Module
Variabel lokal, konstanta lokal, dan variabel statis dicakup ke blok pernyataan tempat variabel tersebut dideklarasikan. Variabel statis khusus karena namanya hanya dapat digunakan sekali di seluruh metode. Misalnya, tidak valid untuk menentukan dua deklarasi variabel statis dengan nama yang sama meskipun berada di blok yang berbeda.
Deklarasi Lokal Implisit
Selain pernyataan deklarasi lokal, variabel lokal juga dapat dinyatakan secara implisit melalui penggunaan. Ekspresi nama sederhana yang menggunakan nama yang tidak mengatasi sesuatu yang lain mendeklarasikan variabel lokal dengan nama tersebut. Contohnya:
Option Explicit Off
Module Test
Sub Main()
x = 10
y = 20
Console.WriteLine(x + y)
End Sub
End Module
Deklarasi lokal implisit hanya terjadi dalam konteks ekspresi yang dapat menerima ekspresi yang diklasifikasikan sebagai variabel. Pengecualian untuk aturan ini adalah bahwa variabel lokal mungkin tidak dideklarasikan secara implisit ketika merupakan target ekspresi pemanggilan fungsi, ekspresi pengindeksan, atau ekspresi akses anggota.
Lokal implisit diperlakukan seolah-olah mereka dinyatakan pada awal metode yang berisi. Dengan demikian, mereka selalu tercakup ke seluruh isi metode, bahkan jika dinyatakan di dalam ekspresi lambda. Misalnya, kode berikut:
Option Explicit Off
Module Test
Sub Main()
Dim x = Sub()
a = 10
End Sub
Dim y = Sub()
Console.WriteLine(a)
End Sub
x()
y()
End Sub
End Module
akan mencetak nilai 10. Lokal implisit ditik seolah-olah Object tidak ada karakter jenis yang dilampirkan ke nama variabel; jika tidak, jenis variabel adalah jenis karakter jenis. Inferensi jenis variabel lokal tidak digunakan untuk lokal implisit.
Jika deklarasi lokal eksplisit ditentukan oleh lingkungan kompilasi atau oleh Option Explicit, semua variabel lokal harus dideklarasikan secara eksplisit dan deklarasi variabel implisit tidak diizinkan.
Dengan Pernyataan
Pernyataan With memungkinkan beberapa referensi ke anggota ekspresi tanpa menentukan ekspresi beberapa kali.
WithStatement
: 'With' Expression StatementTerminator
Block?
'End' 'With' StatementTerminator
;
Ekspresi harus diklasifikasikan sebagai nilai dan dievaluasi sekali, setelah masuk ke blok.
With Dalam blok pernyataan, ekspresi akses anggota atau ekspresi akses kamus yang dimulai dengan titik atau tanda seru dievaluasi seolah-olah With ekspresi mendahuluinya. Contohnya:
Structure Test
Public x As Integer
Function F() As Integer
Return 10
End Function
End Structure
Module TestModule
Sub Main()
Dim y As Test
With y
.x = 10
Console.WriteLine(.x)
.x = .F()
End With
End Sub
End Module
Ini tidak valid untuk bercabang With ke blok pernyataan dari luar blok.
Pernyataan SyncLock
Pernyataan SyncLock memungkinkan pernyataan disinkronkan pada ekspresi, yang memastikan bahwa beberapa utas eksekusi tidak menjalankan pernyataan yang sama pada saat yang sama.
SyncLockStatement
: 'SyncLock' Expression StatementTerminator
Block?
'End' 'SyncLock' StatementTerminator
;
Ekspresi harus diklasifikasikan sebagai nilai dan dievaluasi sekali, setelah masuk ke blok. Saat memasukkan SyncLock blok, Shared metode System.Threading.Monitor.Enter dipanggil pada ekspresi yang ditentukan, yang memblokir hingga utas eksekusi memiliki kunci eksklusif pada objek yang dikembalikan oleh ekspresi. Jenis ekspresi dalam SyncLock pernyataan harus merupakan jenis referensi. Contohnya:
Class Test
Private count As Integer = 0
Public Function Add() As Integer
SyncLock Me
count += 1
Add = count
End SyncLock
End Function
Public Function Subtract() As Integer
SyncLock Me
count -= 1
Subtract = count
End SyncLock
End Function
End Class
Contoh di atas menyinkronkan pada instans kelas Test tertentu untuk memastikan bahwa tidak lebih dari satu utas eksekusi dapat menambahkan atau mengurangi dari variabel hitungan pada satu waktu untuk instans tertentu.
SyncLock Blok secara implisit Shared dimuat oleh Try pernyataan yang bloknya Finally memanggil metode System.Threading.Monitor.Exit pada ekspresi. Ini memastikan kunci dibesarkan bahkan ketika pengecualian dilemparkan. Akibatnya, tidak valid untuk bercabang ke blok SyncLock dari luar blok, dan SyncLock blok diperlakukan sebagai pernyataan tunggal untuk tujuan Resume dan Resume Next. Contoh di atas setara dengan kode berikut:
Class Test
Private count As Integer = 0
Public Function Add() As Integer
Try
System.Threading.Monitor.Enter(Me)
count += 1
Add = count
Finally
System.Threading.Monitor.Exit(Me)
End Try
End Function
Public Function Subtract() As Integer
Try
System.Threading.Monitor.Enter(Me)
count -= 1
Subtract = count
Finally
System.Threading.Monitor.Exit(Me)
End Try
End Function
End Class
Pernyataan Peristiwa
Pernyataan RaiseEvent, AddHandler, dan RemoveHandler meningkatkan peristiwa dan menangani peristiwa secara dinamis.
EventStatement
: RaiseEventStatement
| AddHandlerStatement
| RemoveHandlerStatement
;
Pernyataan RaiseEvent
Pernyataan RaiseEvent memberi tahu penanganan aktivitas bahwa peristiwa tertentu telah terjadi.
RaiseEventStatement
: 'RaiseEvent' IdentifierOrKeyword
( OpenParenthesis ArgumentList? CloseParenthesis )? StatementTerminator
;
Ekspresi nama sederhana dalam pernyataan ditafsirkan RaiseEvent sebagai pencarian anggota di Me. Dengan demikian, RaiseEvent x ditafsirkan seolah-olah itu RaiseEvent Me.x. Hasil ekspresi harus diklasifikasikan sebagai akses peristiwa untuk peristiwa yang ditentukan di kelas itu sendiri; peristiwa yang ditentukan pada jenis dasar tidak dapat digunakan dalam pernyataan RaiseEvent .
Pernyataan diproses RaiseEvent sebagai panggilan ke Invoke metode delegasi peristiwa, menggunakan parameter yang disediakan, jika ada. Jika nilai delegasi adalah Nothing, tidak ada pengecualian yang dilemparkan. Jika tidak ada argumen, tanda kurung mungkin dihilangkan. Contohnya:
Class Raiser
Public Event E1(Count As Integer)
Public Sub Raise()
Static RaiseCount As Integer = 0
RaiseCount += 1
RaiseEvent E1(RaiseCount)
End Sub
End Class
Module Test
Private WithEvents x As Raiser
Private Sub E1Handler(Count As Integer) Handles x.E1
Console.WriteLine("Raise #" & Count)
End Sub
Public Sub Main()
x = New Raiser
x.Raise() ' Prints "Raise #1".
x.Raise() ' Prints "Raise #2".
x.Raise() ' Prints "Raise #3".
End Sub
End Module
Raiser Kelas di atas setara dengan:
Class Raiser
Public Event E1(Count As Integer)
Public Sub Raise()
Static RaiseCount As Integer = 0
Dim TemporaryDelegate As E1EventHandler
RaiseCount += 1
' Use a temporary to avoid a race condition.
TemporaryDelegate = E1Event
If Not TemporaryDelegate Is Nothing Then
TemporaryDelegate.Invoke(RaiseCount)
End If
End Sub
End Class
Pernyataan AddHandler dan RemoveHandler
Meskipun sebagian besar penanganan aktivitas secara otomatis dikaitkan melalui WithEvents variabel, mungkin perlu untuk menambahkan dan menghapus penanganan aktivitas secara dinamis pada waktu proses.
AddHandler dan RemoveHandler pernyataan melakukan hal ini.
AddHandlerStatement
: 'AddHandler' Expression Comma Expression StatementTerminator
;
RemoveHandlerStatement
: 'RemoveHandler' Expression Comma Expression StatementTerminator
;
Setiap pernyataan mengambil dua argumen: argumen pertama harus berupa ekspresi yang diklasifikasikan sebagai akses peristiwa dan argumen kedua harus berupa ekspresi yang diklasifikasikan sebagai nilai. Jenis argumen kedua harus berupa jenis delegasi yang terkait dengan akses peristiwa. Contohnya:
Public Class Form1
Public Sub New()
' Add Button1_Click as an event handler for Button1's Click event.
AddHandler Button1.Click, AddressOf Button1_Click
End Sub
Private Button1 As Button = New Button()
Sub Button1_Click(sender As Object, e As EventArgs)
Console.WriteLine("Button1 was clicked!")
End Sub
Public Sub Disconnect()
RemoveHandler Button1.Click, AddressOf Button1_Click
End Sub
End Class
Mengingat peristiwa, E, pernyataan memanggil metode atau remove_E yang relevan add_E pada instans untuk menambahkan atau menghapus delegasi sebagai handler untuk peristiwa tersebut. Dengan demikian, kode di atas setara dengan:
Public Class Form1
Public Sub New()
Button1.add_Click(AddressOf Button1_Click)
End Sub
Private Button1 As Button = New Button()
Sub Button1_Click(sender As Object, e As EventArgs)
Console.WriteLine("Button1 was clicked!")
End Sub
Public Sub Disconnect()
Button1.remove_Click(AddressOf Button1_Click)
End Sub
End Class
Pernyataan Penugasan
Pernyataan penugasan menetapkan nilai ekspresi ke variabel. Ada beberapa jenis penugasan.
AssignmentStatement
: RegularAssignmentStatement
| CompoundAssignmentStatement
| MidAssignmentStatement
;
Pernyataan Penugasan Reguler
Pernyataan penugasan sederhana menyimpan hasil ekspresi dalam variabel.
RegularAssignmentStatement
: Expression Equals Expression StatementTerminator
;
Ekspresi di sisi kiri operator penugasan harus diklasifikasikan sebagai variabel atau akses properti, sementara ekspresi di sisi kanan operator penugasan harus diklasifikasikan sebagai nilai. Jenis ekspresi harus secara implisit dapat dikonversi ke jenis variabel atau akses properti.
Jika variabel yang ditetapkan ke dalam adalah elemen array dari jenis referensi, pemeriksaan run-time akan dilakukan untuk memastikan bahwa ekspresi kompatibel dengan jenis elemen array. Dalam contoh berikut, penetapan terakhir menyebabkan dilemparkan, karena instans System.ArrayTypeMismatchExceptionArrayList tidak dapat disimpan dalam elemen String array.
Dim sa(10) As String
Dim oa As Object() = sa
oa(0) = Nothing ' This is allowed.
oa(1) = "Hello" ' This is allowed.
oa(2) = New ArrayList() ' System.ArrayTypeMismatchException is thrown.
Jika ekspresi di sisi kiri operator penugasan diklasifikasikan sebagai variabel, maka pernyataan penugasan menyimpan nilai dalam variabel. Jika ekspresi diklasifikasikan sebagai akses properti, maka pernyataan penugasan mengubah akses properti menjadi pemanggilan Set aksesor properti dengan nilai yang digantikan untuk parameter nilai. Contohnya:
Module Test
Private PValue As Integer
Public Property P As Integer
Get
Return PValue
End Get
Set (Value As Integer)
PValue = Value
End Set
End Property
Sub Main()
' The following two lines are equivalent.
P = 10
set_P(10)
End Sub
End Module
Jika target variabel atau akses properti di ketik sebagai jenis nilai tetapi tidak diklasifikasikan sebagai variabel, kesalahan waktu kompilasi terjadi. Contohnya:
Structure S
Public F As Integer
End Structure
Class C
Private PValue As S
Public Property P As S
Get
Return PValue
End Get
Set (Value As S)
PValue = Value
End Set
End Property
End Class
Module Test
Sub Main()
Dim ct As C = New C()
Dim rt As Object = new C()
' Compile-time error: ct.P not classified as variable.
ct.P.F = 10
' Run-time exception.
rt.P.F = 10
End Sub
End Module
Perhatikan bahwa semantik penugasan bergantung pada jenis variabel atau properti yang ditetapkan. Jika variabel yang ditetapkan adalah jenis nilai, penetapan menyalin nilai ekspresi ke dalam variabel. Jika variabel yang ditetapkan adalah jenis referensi, penugasan menyalin referensi, bukan nilai itu sendiri, ke dalam variabel. Jika jenis variabel adalah Object, semantik penugasan ditentukan oleh apakah jenis nilai adalah jenis nilai atau jenis referensi pada waktu proses.
Nota. Untuk jenis intrinsik seperti Integer dan Date, semantik penetapan referensi dan nilai sama karena jenisnya tidak dapat diubah. Akibatnya, bahasa bebas untuk menggunakan penetapan referensi pada jenis intrinsik kotak sebagai pengoptimalan. Dari perspektif nilai, hasilnya sama.
Karena karakter yang sama (=) digunakan baik untuk penugasan maupun untuk kesetaraan, ada ambiguitas antara penugasan sederhana dan pernyataan pemanggilan dalam situasi seperti x = y.ToString(). Dalam semua kasus seperti itu, pernyataan penugasan lebih diutamakan daripada operator kesetaraan. Ini berarti bahwa ekspresi contoh ditafsirkan sebagai x = (y.ToString()) bukan (x = y).ToString().
Pernyataan Penugasan Gabungan
Pernyataan penetapan majemuk mengambil formulir V op= E (di mana op adalah operator biner yang valid).
CompoundAssignmentStatement
: Expression CompoundBinaryOperator LineTerminator? Expression StatementTerminator
;
CompoundBinaryOperator
: '^' '=' | '*' '=' | '/' '=' | '\\' '=' | '+' '=' | '-' '='
| '&' '=' | '<' '<' '=' | '>' '>' '='
;
Ekspresi di sisi kiri operator penugasan harus diklasifikasikan sebagai variabel atau akses properti, sementara ekspresi di sisi kanan operator penugasan harus diklasifikasikan sebagai nilai. Pernyataan penetapan mampul setara dengan pernyataan V = V op E dengan perbedaan bahwa variabel di sisi kiri operator penetapan senyawa hanya dievaluasi sekali. Contoh berikut menunjukkan perbedaan ini:
Module Test
Function GetIndex() As Integer
Console.WriteLine("Getting index")
Return 1
End Function
Sub Main()
Dim a(2) As Integer
Console.WriteLine("Simple assignment")
a(GetIndex()) = a(GetIndex()) + 1
Console.WriteLine("Compound assignment")
a(GetIndex()) += 1
End Sub
End Module
Ekspresi a(GetIndex()) dievaluasi dua kali untuk penugasan sederhana tetapi hanya sekali untuk penetapan majemuk, sehingga kode mencetak:
Simple assignment
Getting index
Getting index
Compound assignment
Getting index
Pernyataan Penugasan Tengah
Pernyataan Mid penugasan menetapkan string ke string lain. Sisi kiri penugasan memiliki sintaks yang sama dengan panggilan ke fungsi Microsoft.VisualBasic.Strings.Mid.
MidAssignmentStatement
: 'Mid' '$'? OpenParenthesis Expression Comma Expression
( Comma Expression )? CloseParenthesis Equals Expression StatementTerminator
;
Argumen pertama adalah target penugasan dan harus diklasifikasikan sebagai variabel atau akses properti yang jenisnya secara implisit dapat dikonversi ke dan dari String. Parameter kedua adalah posisi mulai berbasis 1 yang sesuai dengan di mana penugasan harus dimulai dalam string target dan harus diklasifikasikan sebagai nilai yang jenisnya harus dikonversi secara implisit ke Integer. Parameter ketiga opsional adalah jumlah karakter dari nilai sisi kanan untuk ditetapkan ke dalam string target dan harus diklasifikasikan sebagai nilai yang jenisnya secara implisit dapat dikonversi ke Integer. Sisi kanan adalah string sumber dan harus diklasifikasikan sebagai nilai yang jenisnya secara implisit dapat dikonversi ke String. Sisi kanan dipotong ke parameter panjang, jika ditentukan, dan mengganti karakter dalam string sisi kiri, dimulai dari posisi awal. Jika string sisi kanan berisi lebih sedikit karakter daripada parameter ketiga, hanya karakter dari string sisi kanan yang akan disalin.
Contoh berikut menampilkan ab123fg:
Module Test
Sub Main()
Dim s1 As String = "abcdefg"
Dim s2 As String = "1234567"
Mid$(s1, 3, 3) = s2
Console.WriteLine(s1)
End Sub
End Module
Nota.
Mid bukan kata yang dipesan.
Pernyataan Pemanggilan
Pernyataan pemanggilan memanggil metode yang didahului oleh kata kunci Callopsional . Pernyataan pemanggilan diproses dengan cara yang sama seperti ekspresi pemanggilan fungsi, dengan beberapa perbedaan yang disebutkan di bawah ini. Ekspresi pemanggilan harus diklasifikasikan sebagai nilai atau batal. Nilai apa pun yang dihasilkan dari evaluasi ekspresi pemanggilan dibuang.
Call Jika kata kunci dihilangkan, maka ekspresi pemanggilan harus dimulai dengan pengidentifikasi atau kata kunci, atau dengan . di dalam With blok. Jadi, misalnya, "Call 1.ToString()" adalah pernyataan yang valid tetapi "1.ToString()" tidak. (Perhatikan bahwa dalam konteks ekspresi, ekspresi pemanggilan juga tidak perlu dimulai dengan pengidentifikasi. Misalnya, "Dim x = 1.ToString()" adalah pernyataan yang valid).
Ada perbedaan lain antara pernyataan pemanggilan dan ekspresi pemanggilan: jika pernyataan pemanggilan menyertakan daftar argumen, maka ini selalu diambil sebagai daftar argumen pemanggilan. Contoh berikut mengilustrasikan perbedaannya:
Module Test
Sub Main()
Call {Function() 15}(0)
' error: (0) is taken as argument list, but array is not invokable
Call ({Function() 15}(0))
' valid, since the invocation statement has no argument list
Dim x = {Function() 15}(0)
' valid as an expression, since (0) is taken as an array-indexing
Call f("a")
' error: ("a") is taken as argument list to the invocation of f
Call f()("a")
' valid, since () is the argument list for the invocation of f
Dim y = f("a")
' valid as an expression, since f("a") is interpreted as f()("a")
End Sub
Sub f() As Func(Of String,String)
Return Function(x) x
End Sub
End Module
InvocationStatement
: 'Call'? InvocationExpression StatementTerminator
;
Pernyataan Bersyarah
Pernyataan kondisional memungkinkan eksekusi pernyataan kondisional berdasarkan ekspresi yang dievaluasi pada waktu proses.
ConditionalStatement
: IfStatement
| SelectStatement
;
Kalau... Kemudian... Pernyataan Lain
Pernyataan If...Then...Else adalah pernyataan kondisi dasar.
IfStatement
: BlockIfStatement
| LineIfThenStatement
;
BlockIfStatement
: 'If' BooleanExpression 'Then'? StatementTerminator
Block?
ElseIfStatement*
ElseStatement?
'End' 'If' StatementTerminator
;
ElseIfStatement
: ElseIf BooleanExpression 'Then'? StatementTerminator
Block?
;
ElseStatement
: 'Else' StatementTerminator
Block?
;
LineIfThenStatement
: 'If' BooleanExpression 'Then' Statements ( 'Else' Statements )? StatementTerminator
;
ElseIf
: 'ElseIf'
| 'Else' 'If'
;
Setiap ekspresi dalam If...Then...Else pernyataan harus berupa ekspresi Boolean, sesuai Bagian Ekspresi Boolean. (Catatan: ini tidak mengharuskan ekspresi memiliki jenis Boolean). Jika ekspresi dalam If pernyataan benar, pernyataan yang diapit oleh If blok dijalankan. Jika ekspresi salah, setiap ElseIf ekspresi dievaluasi. Jika salah ElseIf satu ekspresi mengevaluasi ke true, blok yang sesuai dijalankan. Jika tidak ada ekspresi yang mengevaluasi ke true dan ada Else blok, Else blok dijalankan. Setelah blok selesai dieksekusi, eksekusi diteruskan ke akhir If...Then...Else pernyataan.
Versi If baris pernyataan memiliki satu set pernyataan yang akan dijalankan jika If ekspresi adalah True dan sekumpulan pernyataan opsional yang akan dijalankan jika ekspresinya adalah False. Contohnya:
Module Test
Sub Main()
Dim a As Integer = 10
Dim b As Integer = 20
' Block If statement.
If a < b Then
a = b
Else
b = a
End If
' Line If statement
If a < b Then a = b Else b = a
End Sub
End Module
Versi baris pernyataan If mengikat kurang erat daripada ":", dan ikatannya ElseIf ke terdekat secara leksikal sebelumnya yang diizinkan oleh sintaks. Misalnya, dua versi berikut ini setara:
If True Then _
If True Then Console.WriteLine("a") Else Console.WriteLine("b") _
Else Console.WriteLine("c") : Console.WriteLine("d")
If True Then
If True Then
Console.WriteLine("a")
Else
Console.WriteLine("b")
End If
Console.WriteLine("c") : Console.WriteLine("d")
End If
Semua pernyataan selain pernyataan deklarasi label diizinkan di dalam pernyataan baris If , termasuk pernyataan blok. Namun, mereka mungkin tidak menggunakan LineTerminators sebagai StatementTerminators kecuali di dalam ekspresi lambda multi-baris. Contohnya:
' Allowed, since it uses : instead of LineTerminator to separate statements
If b Then With New String("a"(0),5) : Console.WriteLine(.Length) : End With
' Disallowed, since it uses a LineTerminator
If b then With New String("a"(0), 5)
Console.WriteLine(.Length)
End With
' Allowed, since it only uses LineTerminator inside a multi-line lambda
If b Then Call Sub()
Console.WriteLine("a")
End Sub.Invoke()
Pilih Pernyataan Kasus
Pernyataan Select Case menjalankan pernyataan berdasarkan nilai ekspresi.
SelectStatement
: 'Select' 'Case'? Expression StatementTerminator
CaseStatement*
CaseElseStatement?
'End' 'Select' StatementTerminator
;
CaseStatement
: 'Case' CaseClauses StatementTerminator
Block?
;
CaseClauses
: CaseClause ( Comma CaseClause )*
;
CaseClause
: ( 'Is' LineTerminator? )? ComparisonOperator LineTerminator? Expression
| Expression ( 'To' Expression )?
;
ComparisonOperator
: '=' | '<' '>' | '<' | '>' | '>' '=' | '<' '='
;
CaseElseStatement
: 'Case' 'Else' StatementTerminator
Block?
;
Ekspresi harus diklasifikasikan sebagai nilai.
Select Case Ketika pernyataan dijalankan, Select ekspresi dievaluasi terlebih dahulu, dan Case pernyataan kemudian dievaluasi dalam urutan deklarasi tekstual. Pernyataan pertama Case yang mengevaluasi agar True bloknya dijalankan. Jika tidak ada Case pernyataan yang mengevaluasi ke True dan ada Case Else pernyataan, blok tersebut dijalankan. Setelah blok selesai dieksekusi, eksekusi akan diteruskan ke akhir Select pernyataan.
Eksekusi Case blok tidak diizinkan untuk "jatuh melalui" ke bagian sakelar berikutnya. Ini mencegah kelas umum bug yang terjadi dalam bahasa lain ketika Case pernyataan penghentian secara tidak sengaja dihilangkan. Contoh berikut mengilustrasikan perilaku ini:
Module Test
Sub Main()
Dim x As Integer = 10
Select Case x
Case 5
Console.WriteLine("x = 5")
Case 10
Console.WriteLine("x = 10")
Case 20 - 10
Console.WriteLine("x = 20 - 10")
Case 30
Console.WriteLine("x = 30")
End Select
End Sub
End Module
Kode mencetak:
x = 10
Meskipun Case 10 dan Case 20 - 10 memilih untuk nilai yang sama, Case 10 dijalankan karena mendahului Case 20 - 10 secara tekstual. Ketika berikutnya Case tercapai, eksekusi berlanjut setelah Select pernyataan.
Klausa Case mungkin mengambil dua formulir. Salah satu bentuknya adalah kata kunci opsional Is , operator perbandingan, dan ekspresi. Ekspresi dikonversi ke jenis Select ekspresi; jika ekspresi tidak secara implisit dapat dikonversi ke jenis Select ekspresi, kesalahan waktu kompilasi terjadi.
Select Jika ekspresinya adalah E, operator perbandingannya adalah Op, dan Case ekspresinya adalah E1, huruf besar/kecil dievaluasi sebagai E OP E1. Operator harus valid untuk jenis dua ekspresi; jika tidak, kesalahan waktu kompilasi terjadi.
Formulir lainnya adalah ekspresi yang secara opsional diikuti oleh kata kunci To dan ekspresi kedua. Kedua ekspresi dikonversi ke jenis Select ekspresi; jika salah satu ekspresi tidak secara implisit dapat dikonversi ke jenis Select ekspresi, kesalahan waktu kompilasi terjadi.
Select Jika ekspresi adalah E, ekspresi pertama Case adalah E1, dan ekspresi kedua Case adalah E2, Case dievaluasi baik sebagai E = E1 (jika tidak E2 ditentukan) atau (E >= E1) And (E <= E2). Operator harus valid untuk jenis dua ekspresi; jika tidak, kesalahan waktu kompilasi terjadi.
Pernyataan Perulangan
Pernyataan perulangan memungkinkan eksekusi berulang dari pernyataan dalam tubuh mereka.
LoopStatement
: WhileStatement
| DoLoopStatement
| ForStatement
| ForEachStatement
;
Setiap kali isi perulangan dimasukkan, salinan baru terbuat dari semua variabel lokal yang dideklarasikan dalam isi tersebut, diinisialisasi ke nilai variabel sebelumnya. Setiap referensi ke variabel dalam isi perulangan akan menggunakan salinan yang terakhir dibuat. Kode ini menunjukkan contoh:
Module Test
Sub Main()
Dim lambdas As New List(Of Action)
Dim x = 1
For i = 1 To 3
x = i
Dim y = x
lambdas.Add(Sub() Console.WriteLine(x & y))
Next
For Each lambda In lambdas
lambda()
Next
End Sub
End Module
Kode menghasilkan output:
31 32 33
Ketika isi perulangan dijalankan, ia menggunakan salinan variabel mana pun yang saat ini. Misalnya, pernyataan Dim y = x mengacu pada salinan terbaru dan y salinan asli .x Dan ketika lambda dibuat, ia mengingat salinan variabel mana yang saat ini dibuat. Oleh karena itu, setiap lambda menggunakan salinan bersama yang sama dari x, tetapi salinan yang berbeda dari y. Di akhir program, ketika menjalankan lambda, salinan x bersama yang mereka semua rujuk sekarang berada pada nilai akhir 3.
Perhatikan bahwa jika tidak ada ekspresi lambda atau LINQ, maka tidak mungkin untuk mengetahui bahwa salinan baru dibuat pada entri perulangan. Memang, pengoptimalan kompilator akan menghindari pembuatan salinan dalam kasus ini. Perhatikan juga bahwa itu ilegal untuk GoTo ke dalam perulangan yang berisi ekspresi lambda atau LINQ.
Sambil... Akhiri Sementara dan Lakukan... Pernyataan Perulangan
Pernyataan While perulangan atau Do loop berdasarkan ekspresi Boolean.
WhileStatement
: 'While' BooleanExpression StatementTerminator
Block?
'End' 'While' StatementTerminator
;
DoLoopStatement
: DoTopLoopStatement
| DoBottomLoopStatement
;
DoTopLoopStatement
: 'Do' ( WhileOrUntil BooleanExpression )? StatementTerminator
Block?
'Loop' StatementTerminator
;
DoBottomLoopStatement
: 'Do' StatementTerminator
Block?
'Loop' WhileOrUntil BooleanExpression StatementTerminator
;
WhileOrUntil
: 'While' | 'Until'
;
Pernyataan While perulangan mengulang selama ekspresi Boolean mengevaluasi ke true; Do pernyataan perulangan mungkin berisi kondisi yang lebih kompleks. Ekspresi dapat ditempatkan setelah Do kata kunci atau setelah Loop kata kunci, tetapi tidak setelah keduanya. Ekspresi Boolean dievaluasi sesuai Bagian Ekspresi Boolean. (Catatan: ini tidak mengharuskan ekspresi memiliki jenis Boolean). Hal ini juga valid untuk menentukan tidak ada ekspresi sedikitpun; dalam hal ini, perulangan tidak akan pernah keluar. Jika ekspresi ditempatkan setelah Do, ekspresi akan dievaluasi sebelum blok perulangan dijalankan pada setiap perulangan. Jika ekspresi ditempatkan setelah Loop, ekspresi akan dievaluasi setelah blok perulangan dijalankan pada setiap perulangan. Oleh karena itu, menempatkan ekspresi setelahnya Loop akan menghasilkan satu perulangan lagi daripada penempatan setelah Do. Contoh berikut menunjukkan perilaku ini:
Module Test
Sub Main()
Dim x As Integer
x = 3
Do While x = 1
Console.WriteLine("First loop")
Loop
Do
Console.WriteLine("Second loop")
Loop While x = 1
End Sub
End Module
Kode menghasilkan output:
Second Loop
Dalam kasus perulangan pertama, kondisi dievaluasi sebelum perulangan dijalankan. Dalam kasus perulangan kedua, kondisi dijalankan setelah perulangan dijalankan. Ekspresi bersyariah harus diawali dengan While kata kunci atau Until kata kunci. Yang pertama memutus perulangan jika kondisi mengevaluasi ke false, yang terakhir ketika kondisi mengevaluasi ke true.
Nota.
Until bukan kata yang dipesan.
Bagi... Pernyataan Berikutnya
Pernyataan For...Next mengulang berdasarkan sekumpulan batas. Pernyataan For menentukan variabel kontrol perulangan, ekspresi terikat yang lebih rendah, ekspresi terikat atas, dan ekspresi nilai langkah opsional. Variabel kontrol perulangan ditentukan baik melalui pengidentifikasi diikuti dengan klausa opsional As atau ekspresi.
ForStatement
: 'For' LoopControlVariable Equals Expression 'To' Expression
( 'Step' Expression )? StatementTerminator
Block?
( 'Next' NextExpressionList? StatementTerminator )?
;
LoopControlVariable
: Identifier ( IdentifierModifiers 'As' TypeName )?
| Expression
;
NextExpressionList
: Expression ( Comma Expression )*
;
Sesuai aturan berikut, variabel kontrol perulangan mengacu pada variabel lokal baru khusus untuk pernyataan ini For...Next , atau ke variabel yang sudah ada sebelumnya, atau ke ekspresi.
Jika variabel kontrol perulangan adalah pengidentifikasi dengan
Asklausul, pengidentifikasi menentukan variabel lokal baru dari jenis yang ditentukan dalamAsklausa, dicakup ke seluruhForperulangan.Jika variabel kontrol perulangan adalah pengidentifikasi tanpa
Asklausul, pengidentifikasi pertama kali diselesaikan menggunakan aturan resolusi nama sederhana (lihat Bagian Ekspresi Nama Sederhana), kecuali bahwa kemunculan pengidentifikasi ini tidak akan masuk dan dari dirinya sendiri menyebabkan variabel lokal implisit dibuat (Bagian Deklarasi Lokal Implisit).Jika resolusi ini berhasil dan hasilnya diklasifikasikan sebagai variabel, maka variabel kontrol perulangan adalah variabel yang sudah ada sebelumnya.
Jika resolusi gagal, atau jika resolusi berhasil dan hasilnya diklasifikasikan sebagai jenis, maka:
- jika inferensi jenis variabel lokal sedang digunakan, pengidentifikasi mendefinisikan variabel lokal baru yang jenisnya disimpulkan dari ekspresi terikat dan langkah, terlingkup ke seluruh
Forperulangan; - jika inferensi jenis variabel lokal tidak digunakan tetapi deklarasi lokal implisit adalah, maka variabel lokal implisit dibuat yang cakupannya adalah seluruh metode ( Bagian Deklarasi Lokal Implisit), dan variabel kontrol perulangan mengacu pada variabel yang sudah ada sebelumnya ini;
- jika tidak ada inferensi jenis variabel lokal atau deklarasi lokal implisit yang digunakan, itu adalah kesalahan.
- jika inferensi jenis variabel lokal sedang digunakan, pengidentifikasi mendefinisikan variabel lokal baru yang jenisnya disimpulkan dari ekspresi terikat dan langkah, terlingkup ke seluruh
Jika resolusi berhasil dengan sesuatu yang diklasifikasikan sebagai jenis atau variabel, itu adalah kesalahan.
Jika variabel kontrol perulangan adalah ekspresi, ekspresi harus diklasifikasikan sebagai variabel.
Variabel kontrol perulangan tidak dapat digunakan oleh pernyataan penutup For...Next lain. Jenis variabel kontrol perulangan dari For pernyataan menentukan jenis iterasi dan harus salah satu dari:
-
Byte, ,SByteUShort,Short,UInteger,Integer,ULong,Long,Decimal, , ,SingleDouble - Jenis enumerasi
Object- Jenis
Tyang memiliki operator berikut, di manaBadalah jenis yang dapat digunakan dalam ekspresi Boolean:
Public Shared Operator >= (op1 As T, op2 As T) As B
Public Shared Operator <= (op1 As T, op2 As T) As B
Public Shared Operator - (op1 As T, op2 As T) As T
Public Shared Operator + (op1 As T, op2 As T) As T
Ekspresi terikat dan langkah harus dikonversi secara implisit ke jenis variabel kontrol perulangan dan harus diklasifikasikan sebagai nilai. Pada waktu kompilasi, jenis variabel kontrol perulangan disimpulkan dengan memilih jenis terluas di antara jenis ekspresi terikat bawah, terikat atas, dan langkah. Jika tidak ada konversi yang melebar antara dua jenis, maka terjadi kesalahan waktu kompilasi.
Pada run time, jika jenis variabel kontrol perulangan adalah Object, maka jenis iterasi disimpulkan sama seperti pada waktu kompilasi, dengan dua pengecualian. Pertama, jika ekspresi terikat dan langkah adalah semua jenis integral tetapi tidak memiliki jenis terluas, maka jenis terluas yang mencakup ketiga jenis akan disimpulkan. Dan kedua, jika jenis variabel kontrol perulangan disimpulkan menjadi String, Double akan disimpulkan sebagai gantinya. Jika, pada waktu proses, tidak ada jenis kontrol perulangan yang dapat ditentukan atau jika salah satu ekspresi tidak dapat dikonversi ke jenis kontrol perulangan, System.InvalidCastException akan terjadi. Setelah jenis kontrol perulangan dipilih di awal perulangan, jenis yang sama akan digunakan di seluruh iterasi, terlepas dari perubahan yang dilakukan pada nilai dalam variabel kontrol perulangan.
Pernyataan For harus ditutup oleh pernyataan yang cocok Next . Pernyataan Next tanpa variabel cocok dengan pernyataan terbuka For paling dalam, sementara Next pernyataan dengan satu atau beberapa variabel kontrol perulangan akan, dari kiri ke kanan, cocok For dengan perulangan yang cocok dengan setiap variabel. Jika variabel cocok dengan For perulangan yang bukan perulangan yang paling berlapis pada saat itu, hasil kesalahan waktu kompilasi.
Di awal perulangan, tiga ekspresi dievaluasi dalam urutan tekstual dan ekspresi terikat yang lebih rendah ditetapkan ke variabel kontrol perulangan. Jika nilai langkah dihilangkan, nilai tersebut secara implisit harfiah 1, dikonversi ke jenis variabel kontrol perulangan. Ketiga ekspresi hanya pernah dievaluasi di awal perulangan.
Di awal setiap perulangan, variabel kontrol dibandingkan dengan melihat apakah lebih besar dari titik akhir jika ekspresi langkah positif, atau kurang dari titik akhir jika ekspresi langkah negatif. Jika ya, perulangan For berakhir; jika tidak, blok perulangan dijalankan. Jika variabel kontrol perulangan bukan jenis primitif, operator perbandingan ditentukan oleh apakah ekspresi step >= step - step tersebut benar atau salah.
Next Pada pernyataan, nilai langkah ditambahkan ke variabel kontrol dan eksekusi kembali ke bagian atas perulangan.
Perhatikan bahwa salinan baru variabel kontrol perulangan tidak dibuat pada setiap iterasi blok perulangan. Dalam hal ini, For pernyataan berbeda dari For Each (Bagian Untuk Setiap... Pernyataan Berikutnya).
Tidak valid untuk bercabang ke dalam perulangan For dari luar perulangan.
Untuk masing-masing... Pernyataan Berikutnya
Pernyataan For Each...Next mengulang berdasarkan elemen dalam ekspresi. Pernyataan For Each menentukan variabel kontrol perulangan dan ekspresi enumerator. Variabel kontrol perulangan ditentukan baik melalui pengidentifikasi diikuti dengan klausa opsional As atau ekspresi.
ForEachStatement
: 'For' 'Each' LoopControlVariable 'In' LineTerminator? Expression StatementTerminator
Block?
( 'Next' NextExpressionList? StatementTerminator )?
;
Mengikuti aturan yang sama dengan For...Next pernyataan (Bagian Untuk... Pernyataan Berikutnya), variabel kontrol perulangan mengacu pada variabel lokal baru khusus untuk ini Untuk Setiap... Pernyataan berikutnya, atau ke variabel yang sudah ada sebelumnya, atau ke ekspresi.
Ekspresi enumerator harus diklasifikasikan sebagai nilai dan jenisnya harus merupakan jenis koleksi atau Object. Jika jenis ekspresi enumerator adalah Object, maka semua pemrosesan ditangguhkan hingga run-time. Jika tidak, konversi harus ada dari jenis elemen koleksi ke jenis variabel kontrol perulangan.
Variabel kontrol perulangan tidak dapat digunakan oleh pernyataan penutup For Each lain. Pernyataan For Each harus ditutup oleh pernyataan yang cocok Next . Pernyataan Next tanpa variabel kontrol perulangan cocok dengan yang paling dalam terbuka For Each. Pernyataan Next dengan satu atau beberapa variabel kontrol perulangan akan, dari kiri ke kanan, cocok For Each dengan perulangan yang memiliki variabel kontrol perulangan yang sama. Jika variabel cocok dengan For Each perulangan yang bukan perulangan yang paling berlapis pada saat itu, kesalahan waktu kompilasi terjadi.
Jenis C dikatakan sebagai jenis koleksi jika salah satu dari:
Semua hal berikut ini benar:
-
Cberisi instans, metode bersama, atau ekstensi yang dapat diakses dengan tanda tanganGetEnumerator()yang mengembalikan jenisE. -
Eberisi instans, metode bersama, atau ekstensi yang dapat diakses dengan tanda tanganMoveNext()dan jenisBooleanpengembalian . -
Eberisi instans yang dapat diakses atau properti bersama bernamaCurrentyang memiliki getter. Jenis properti ini adalah jenis elemen dari jenis koleksi.
-
Ini mengimplementasikan antarmuka
System.Collections.Generic.IEnumerable(Of T), dalam hal ini jenis elemen koleksi dianggapTsebagai .Ini mengimplementasikan antarmuka
System.Collections.IEnumerable, dalam hal ini jenis elemen koleksi dianggapObjectsebagai .
Berikut ini adalah contoh kelas yang dapat dijumlahkan:
Public Class IntegerCollection
Private integers(10) As Integer
Public Class IntegerCollectionEnumerator
Private collection As IntegerCollection
Private index As Integer = -1
Friend Sub New(c As IntegerCollection)
collection = c
End Sub
Public Function MoveNext() As Boolean
index += 1
Return index <= 10
End Function
Public ReadOnly Property Current As Integer
Get
If index < 0 OrElse index > 10 Then
Throw New System.InvalidOperationException()
End If
Return collection.integers(index)
End Get
End Property
End Class
Public Sub New()
Dim i As Integer
For i = 0 To 10
integers(i) = I
Next i
End Sub
Public Function GetEnumerator() As IntegerCollectionEnumerator
Return New IntegerCollectionEnumerator(Me)
End Function
End Class
Sebelum perulangan dimulai, ekspresi enumerator dievaluasi. Jika jenis ekspresi tidak memenuhi pola desain, maka ekspresi dilemparkan ke System.Collections.IEnumerable atau System.Collections.Generic.IEnumerable(Of T). Jika jenis ekspresi mengimplementasikan antarmuka generik, antarmuka generik lebih disukai pada waktu kompilasi tetapi antarmuka non-generik lebih disukai pada run-time. Jika jenis ekspresi mengimplementasikan antarmuka generik beberapa kali, pernyataan dianggap ambigu dan terjadi kesalahan waktu kompilasi.
Nota. Antarmuka non-generik lebih disukai dalam kasus terikat akhir, karena memilih antarmuka generik berarti bahwa semua panggilan ke metode antarmuka akan melibatkan parameter jenis. Karena tidak dimungkinkan untuk mengetahui argumen jenis yang cocok pada run-time, semua panggilan tersebut harus dilakukan menggunakan panggilan yang terlambat terikat. Ini akan lebih lambat daripada memanggil antarmuka non-generik karena antarmuka non-generik dapat dipanggil menggunakan panggilan waktu kompilasi.
GetEnumerator dipanggil pada nilai yang dihasilkan dan nilai pengembalian fungsi disimpan dalam sementara. Kemudian pada awal setiap iterasi, MoveNext dipanggil pada sementara. Jika mengembalikan False, perulangan akan berakhir. Jika tidak, setiap iterasi perulangan dijalankan sebagai berikut:
- Jika variabel kontrol perulangan mengidentifikasi variabel lokal baru (bukan variabel yang sudah ada sebelumnya), salinan baru variabel lokal ini dibuat. Untuk iterasi saat ini, semua referensi dalam blok perulangan akan merujuk ke salinan ini.
- Properti
Currentdiambil, dikoercasi ke jenis variabel kontrol perulangan (terlepas dari apakah konversi implisit atau eksplisit), dan ditetapkan ke variabel kontrol perulangan. - Blok perulangan dijalankan.
Nota. Ada sedikit perubahan perilaku antara bahasa versi 10.0 dan 11.0. Sebelum 11.0, variabel iterasi segar tidak dibuat untuk setiap perulangan perulangan. Perbedaan ini hanya dapat diamati jika variabel iterasi ditangkap oleh lambda atau ekspresi LINQ yang kemudian dipanggil setelah perulangan:
Dim lambdas As New List(Of Action)
For Each x In {1,2,3}
lambdas.Add(Sub() Console.WriteLine(x)
Next
lambdas(0).Invoke()
lambdas(1).Invoke()
lambdas(2).Invoke()
Hingga Visual Basic 10.0, ini menghasilkan peringatan pada waktu kompilasi dan dicetak "3" tiga kali. Itu karena hanya ada satu variabel "x" yang dibagikan oleh semua iterasi perulangan, dan ketiga lambda menangkap "x" yang sama, dan pada saat lambda dijalankan kemudian memegang angka 3. Pada Visual Basic 11.0, ia mencetak "1, 2, 3". Itu karena setiap lambda menangkap variabel yang berbeda "x".
Nota. Elemen iterasi saat ini dikonversi ke jenis variabel kontrol perulangan bahkan jika konversi eksplisit karena tidak ada tempat yang nyaman untuk memperkenalkan operator konversi dalam pernyataan. Ini menjadi sangat merepotkan ketika bekerja dengan jenis System.Collections.ArrayListyang sekarang usang , karena jenis elemennya adalah Object. Ini akan membutuhkan cast dalam banyak perulangan, sesuatu yang kami rasa tidak ideal. Ironisnya, generik mengaktifkan pembuatan koleksi yang sangat diketik, System.Collections.Generic.List(Of T), yang mungkin telah membuat kita memikirkan kembali titik desain ini, tetapi demi kompatibilitas, ini tidak dapat diubah sekarang.
Next Ketika pernyataan tercapai, eksekusi kembali ke bagian atas perulangan. Jika variabel ditentukan setelah Next kata kunci, variabel harus sama dengan variabel pertama setelah For Each. Misalnya, pertimbangkan kode berikut:
Module Test
Sub Main()
Dim i As Integer
Dim c As IntegerCollection = New IntegerCollection()
For Each i In c
Console.WriteLine(i)
Next i
End Sub
End Module
Ini setara dengan kode berikut:
Module Test
Sub Main()
Dim i As Integer
Dim c As IntegerCollection = New IntegerCollection()
Dim e As IntegerCollection.IntegerCollectionEnumerator
e = c.GetEnumerator()
While e.MoveNext()
i = e.Current
Console.WriteLine(i)
End While
End Sub
End Module
Jika jenis E enumerator mengimplementasikan System.IDisposable, maka enumerator dibuang saat keluar dari perulangan dengan memanggil Dispose metode . Ini memastikan bahwa sumber daya yang dipegang oleh enumerator dirilis. Jika metode yang berisi For Each pernyataan tidak menggunakan penanganan kesalahan yang tidak terstruktur, maka For Each pernyataan dibungkus dalam Try pernyataan dengan metode yang Dispose dipanggil dalam Finally untuk memastikan pembersihan.
Nota. Jenisnya System.Array adalah jenis koleksi, dan karena semua jenis array berasal dari System.Array, ekspresi jenis array apa pun diizinkan dalam pernyataan For Each . Untuk array dimensi tunggal, For Each pernyataan menghitung elemen array dalam meningkatkan urutan indeks, dimulai dengan indeks 0 dan berakhir dengan Panjang indeks - 1. Untuk array multidimensi, indeks dimensi paling kanan ditingkatkan terlebih dahulu.
Misalnya, kode berikut mencetak 1 2 3 4:
Module Test
Sub Main()
Dim x(,) As Integer = { { 1, 2 }, { 3, 4 } }
Dim i As Integer
For Each i In x
Console.Write(i & " ")
Next i
End Sub
End Module
Tidak valid untuk bercabang For Each ke blok pernyataan dari luar blok.
Pernyataan Exception-Handling
Visual Basic mendukung penanganan pengecualian terstruktur dan penanganan pengecualian yang tidak terstruktur. Hanya satu gaya penanganan pengecualian yang dapat digunakan dalam metode, tetapi Error pernyataan dapat digunakan dalam penanganan pengecualian terstruktur. Jika metode menggunakan kedua gaya penanganan pengecualian, hasil kesalahan waktu kompilasi.
ErrorHandlingStatement
: StructuredErrorStatement
| UnstructuredErrorStatement
;
Pernyataan Exception-Handling Terstruktur
Penanganan pengecualian terstruktur adalah metode penanganan kesalahan dengan mendeklarasikan blok eksplisit di mana pengecualian tertentu akan ditangani. Penanganan pengecualian terstruktur dilakukan melalui Try pernyataan.
StructuredErrorStatement
: ThrowStatement
| TryStatement
;
TryStatement
: 'Try' StatementTerminator
Block?
CatchStatement*
FinallyStatement?
'End' 'Try' StatementTerminator
;
Contohnya:
Module Test
Sub ThrowException()
Throw New Exception()
End Sub
Sub Main()
Try
ThrowException()
Catch e As Exception
Console.WriteLine("Caught exception!")
Finally
Console.WriteLine("Exiting try.")
End Try
End Sub
End Module
Pernyataan Try terdiri dari tiga jenis blok: coba blok, tangkap blok, dan akhirnya blok.
Blok coba adalah blok pernyataan yang berisi pernyataan yang akan dijalankan.
Blok tangkapan adalah blok pernyataan yang menangani pengecualian.
Blok akhirnya adalah blok pernyataan yang berisi pernyataan yang akan dijalankan ketika Try pernyataan keluar, terlepas dari apakah pengecualian telah terjadi dan telah ditangani. Pernyataan Try , yang hanya dapat berisi satu blok percobaan dan satu blok akhirnya, harus berisi setidaknya satu blok tangkapan atau akhirnya diblokir. Tidak valid untuk secara eksplisit mentransfer eksekusi ke blok percobaan kecuali dari dalam blok tangkapan dalam pernyataan yang sama.
Akhirnya Blokir
Blok Finally selalu dijalankan saat eksekusi meninggalkan bagian mana pun dari pernyataan Try. Tidak ada tindakan eksplisit yang diperlukan untuk menjalankan Finally blok; ketika eksekusi meninggalkan Try pernyataan, sistem akan secara otomatis menjalankan Finally blok dan kemudian mentransfer eksekusi ke tujuan yang dimaksudkan.
Finally Blok dijalankan terlepas dari bagaimana eksekusi meninggalkan Try pernyataan: melalui akhir Try blok, melalui akhir Catch blok, melalui Exit Try pernyataan, melalui GoTo pernyataan, atau dengan tidak menangani pengecualian yang dilemparkan.
Perhatikan bahwa Await ekspresi dalam metode asinkron, dan Yield pernyataan dalam metode iterator, dapat menyebabkan aliran kontrol ditangguhkan dalam instans metode asinkron atau iterator dan melanjutkan di beberapa instans metode lainnya. Namun, ini hanyalah penangguhan eksekusi dan tidak melibatkan keluar dari metode asinkron atau instans metode iterator masing-masing, sehingga tidak menyebabkan Finally blok dijalankan.
Tidak valid untuk secara eksplisit mentransfer eksekusi ke dalam Finally blok; juga tidak valid untuk mentransfer eksekusi keluar dari Finally blok kecuali melalui pengecualian.
FinallyStatement
: 'Finally' StatementTerminator
Block?
;
Blok Penanganan
Jika pengecualian terjadi saat memproses Try blok, setiap Catch pernyataan diperiksa dalam urutan tekstual untuk menentukan apakah itu menangani pengecualian.
CatchStatement
: 'Catch' ( Identifier ( 'As' NonArrayTypeName )? )?
( 'When' BooleanExpression )? StatementTerminator
Block?
;
Pengidentifikasi yang ditentukan dalam Catch klausul mewakili pengecualian yang telah dilemparkan. Jika pengidentifikasi berisi klausul As , pengidentifikasi dianggap dideklarasikan dalam Catch ruang deklarasi lokal blok. Jika tidak, pengidentifikasi harus berupa variabel lokal (bukan variabel statis) yang ditentukan dalam blok yang berisi.
Klausa Catch tanpa pengidentifikasi akan menangkap semua pengecualian yang berasal dari System.Exception.
Catch Klausa dengan pengidentifikasi hanya akan menangkap pengecualian yang jenisnya sama dengan atau berasal dari jenis pengidentifikasi. Jenisnya harus System.Exception, atau jenis yang berasal dari System.Exception. Ketika pengecualian tertangkap yang berasal dari System.Exception, referensi ke objek pengecualian disimpan dalam objek yang dikembalikan oleh fungsi Microsoft.VisualBasic.Information.Err.
Catch Klausa dengan When klausul hanya akan menangkap pengecualian ketika ekspresi mengevaluasi ke True; jenis ekspresi harus berupa ekspresi Boolean sesuai Bagian Ekspresi Boolean.
When Klausa hanya diterapkan setelah memeriksa jenis pengecualian, dan ekspresi dapat merujuk ke pengidentifikasi yang mewakili pengecualian, seperti yang ditunjukkan contoh ini:
Module Test
Sub Main()
Dim i As Integer = 5
Try
Throw New ArgumentException()
Catch e As OverflowException When i = 5
Console.WriteLine("First handler")
Catch e As ArgumentException When i = 4
Console.WriteLine("Second handler")
Catch When i = 5
Console.WriteLine("Third handler")
End Try
End Sub
End Module
Contoh ini mencetak:
Third handler
Jika klausa Catch menangani pengecualian, eksekusi akan ditransfer ke Catch blok. Di akhir Catch blok, eksekusi ditransfer ke pernyataan pertama setelah Try pernyataan. Pernyataan tidak Try akan menangani pengecualian apa pun yang Catch dilemparkan dalam blok. Jika tidak ada Catch klausa yang menangani pengecualian, eksekusi akan ditransfer ke lokasi yang ditentukan oleh sistem.
Tidak valid untuk secara eksplisit mentransfer eksekusi ke dalam Catch blok.
Filter dalam klausul When biasanya dievaluasi sebelum pengecualian dilemparkan. Misalnya, kode berikut akan mencetak "Filter, Akhirnya, Tangkap".
Sub Main()
Try
Foo()
Catch ex As Exception When F()
Console.WriteLine("Catch")
End Try
End Sub
Sub Foo()
Try
Throw New Exception
Finally
Console.WriteLine("Finally")
End Try
End Sub
Function F() As Boolean
Console.WriteLine("Filter")
Return True
End Function
Namun, metode Asinkron dan Iterator menyebabkan semua blok akhirnya di dalamnya dijalankan sebelum filter apa pun di luar. Misalnya, jika kode di atas memiliki Async Sub Foo(), maka outputnya adalah "Akhirnya, Filter, Tangkap".
Pernyataan Lempar
Pernyataan ini Throw menimbulkan pengecualian, yang diwakili oleh instans jenis yang berasal dari System.Exception.
ThrowStatement
: 'Throw' Expression? StatementTerminator
;
Jika ekspresi tidak diklasifikasikan sebagai nilai atau bukan jenis yang berasal dari System.Exception, maka terjadi kesalahan waktu kompilasi. Jika ekspresi mengevaluasi ke nilai null pada waktu proses, maka System.NullReferenceException pengecualian akan dinaikkan sebagai gantinya.
Pernyataan Throw dapat menghilangkan ekspresi dalam blok Try tangkapan pernyataan, selama tidak ada intervensi akhirnya memblokir. Dalam hal ini, pernyataan menggulung balik pengecualian yang saat ini sedang ditangani dalam blok tangkapan. Contohnya:
Sub Test(x As Integer)
Try
Throw New Exception()
Catch
If x = 0 Then
Throw ' OK, rethrows exception from above.
Else
Try
If x = 1 Then
Throw ' OK, rethrows exception from above.
End If
Finally
Throw ' Invalid, inside of a Finally.
End Try
End If
End Try
End Sub
Pernyataan Exception-Handling tidak terstruktur
Penanganan pengecualian yang tidak terstruktur adalah metode penanganan kesalahan dengan menunjukkan pernyataan untuk bercabang ketika pengecualian terjadi. Penanganan pengecualian yang tidak terstruktur diimplementasikan menggunakan tiga pernyataan: Error pernyataan, On Error pernyataan, dan Resume pernyataan.
UnstructuredErrorStatement
: ErrorStatement
| OnErrorStatement
| ResumeStatement
;
Contohnya:
Module Test
Sub ThrowException()
Error 5
End Sub
Sub Main()
On Error GoTo GotException
ThrowException()
Exit Sub
GotException:
Console.WriteLine("Caught exception!")
Resume Next
End Sub
End Module
Ketika metode menggunakan penanganan pengecualian yang tidak terstruktur, penangan pengecualian terstruktur tunggal dibuat untuk seluruh metode yang menangkap semua pengecualian. (Perhatikan bahwa dalam konstruktor handler ini tidak memperluas panggilan ke panggilan New ke di awal konstruktor.) Metode ini kemudian melacak lokasi penanganan pengecualian terbaru dan pengecualian terbaru yang telah dilemparkan. Pada entri ke metode , lokasi penangan pengecualian dan pengecualian keduanya diatur ke Nothing. Ketika pengecualian dilemparkan dalam metode yang menggunakan penanganan pengecualian yang tidak terstruktur, referensi ke objek pengecualian disimpan dalam objek yang dikembalikan oleh fungsi Microsoft.VisualBasic.Information.Err.
Pernyataan penanganan kesalahan yang tidak terstruktur tidak diizinkan dalam iterator atau metode asinkron.
Pernyataan Kesalahan
Pernyataan Error melemparkan pengecualian yang System.Exception berisi nomor pengecualian Visual Basic 6. Ekspresi harus diklasifikasikan sebagai nilai dan jenisnya harus secara implisit dapat dikonversi ke Integer.
ErrorStatement
: 'Error' Expression StatementTerminator
;
Pada Pernyataan Kesalahan
Pernyataan On Error memodifikasi status penanganan pengecualian terbaru.
OnErrorStatement
: 'On' 'Error' ErrorClause StatementTerminator
;
ErrorClause
: 'GoTo' '-' '1'
| 'GoTo' '0'
| GoToStatement
| 'Resume' 'Next'
;
Ini dapat digunakan dalam salah satu dari empat cara:
On Error GoTo -1mengatur ulang pengecualian terbaru keNothing.On Error GoTo 0mengatur ulang lokasi penanganan pengecualian terbaru keNothing.On Error GoTo LabelNamemenetapkan label sebagai lokasi penanganan pengecualian terbaru. Pernyataan ini tidak dapat digunakan dalam metode yang berisi ekspresi lambda atau kueri.On Error Resume NextResume Nextmenetapkan perilaku sebagai lokasi penanganan pengecualian terbaru.
Pernyataan Lanjutkan
Pernyataan Resume mengembalikan eksekusi ke pernyataan yang menyebabkan pengecualian terbaru.
ResumeStatement
: 'Resume' ResumeClause? StatementTerminator
;
ResumeClause
: 'Next'
| LabelName
;
Jika pengubah Next ditentukan, eksekusi kembali ke pernyataan yang akan dijalankan setelah pernyataan yang menyebabkan pengecualian terbaru. Jika nama label ditentukan, eksekusi akan kembali ke label.
Karena pernyataan berisi SyncLock blok penanganan kesalahan terstruktur implisit, Resume dan Resume Next memiliki perilaku khusus untuk pengecualian yang terjadi dalam SyncLock pernyataan.
Resume mengembalikan eksekusi ke awal SyncLock pernyataan, sementara Resume Next mengembalikan eksekusi ke pernyataan berikutnya setelah SyncLock pernyataan. Misalnya, pertimbangkan kode berikut:
Class LockClass
End Class
Module Test
Sub Main()
Dim FirstTime As Boolean = True
Dim Lock As LockClass = New LockClass()
On Error GoTo Handler
SyncLock Lock
Console.WriteLine("Before exception")
Throw New Exception()
Console.WriteLine("After exception")
End SyncLock
Console.WriteLine("After SyncLock")
Exit Sub
Handler:
If FirstTime Then
FirstTime = False
Resume
Else
Resume Next
End If
End Sub
End Module
Ini mencetak hasil berikut.
Before exception
Before exception
After SyncLock
Pertama kali melalui SyncLock pernyataan, Resume mengembalikan eksekusi ke awal SyncLock pernyataan. Kedua kalinya SyncLock melalui pernyataan, Resume Next mengembalikan eksekusi ke akhir SyncLock pernyataan.
Resume dan Resume Next tidak diizinkan dalam pernyataan SyncLock .
Dalam semua kasus, ketika Resume pernyataan dijalankan, pengecualian terbaru diatur ke Nothing.
Resume Jika pernyataan dijalankan tanpa pengecualian terbaru, pernyataan akan menimbulkan pengecualian yang System.Exception berisi nomor 20 kesalahan Visual Basic (Lanjutkan tanpa kesalahan).
Pernyataan Cabang
Pernyataan cabang mengubah alur eksekusi dalam metode . Ada enam pernyataan cabang:
- Pernyataan
GoTomenyebabkan eksekusi ditransfer ke label yang ditentukan dalam metode . Ini tidak diizinkan untukGoTomasuk ke dalamTry, ,SyncLockUsing,With,ForatauFor Eachblok, atau ke blok perulangan apa pun jika variabel lokal blok tersebut ditangkap dalam ekspresi lambda atau LINQ. - Pernyataan
Exitmentransfer eksekusi ke pernyataan berikutnya setelah akhir pernyataan blok yang segera berisi jenis yang ditentukan. Jika blok adalah blok metode, alur kontrol akan keluar dari metode seperti yang dijelaskan dalam Alur Kontrol Bagian.ExitJika pernyataan tidak terkandung dalam jenis blok yang ditentukan dalam pernyataan, kesalahan waktu kompilasi terjadi. - Pernyataan
Continuementransfer eksekusi ke akhir pernyataan loop blok yang segera berisi jenis yang ditentukan.ContinueJika pernyataan tidak terkandung dalam jenis blok yang ditentukan dalam pernyataan, kesalahan waktu kompilasi terjadi. - Pernyataan
Stopmenyebabkan terjadinya pengecualian debugger. - Pernyataan
Endmengakhiri program. Finalizer dijalankan sebelum dimatikan, tetapi blok akhirnya dari setiap pernyataan yang saat ini dijalankanTrytidak dijalankan. Pernyataan ini mungkin tidak digunakan dalam program yang tidak dapat dieksekusi (misalnya, DLL). - Pernyataan
Returntanpa ekspresi setara denganExit Subpernyataan atauExit Function.ReturnPernyataan dengan ekspresi hanya diizinkan dalam metode reguler yang merupakan fungsi, atau dalam metode asinkron yang merupakan fungsi dengan jenisTask(Of T)pengembalian untuk beberapaT. Ekspresi harus diklasifikasikan sebagai nilai yang secara implisit dapat dikonversi ke variabel pengembalian fungsi (dalam kasus metode reguler) atau ke variabel pengembalian tugas (dalam kasus metode asinkron). Perilakunya adalah mengevaluasi ekspresinya, lalu menyimpannya dalam variabel pengembalian, lalu menjalankan pernyataan implisitExit Function.
BranchStatement
: GoToStatement
| ExitStatement
| ContinueStatement
| StopStatement
| EndStatement
| ReturnStatement
;
GoToStatement
: 'GoTo' LabelName StatementTerminator
;
ExitStatement
: 'Exit' ExitKind StatementTerminator
;
ExitKind
: 'Do' | 'For' | 'While' | 'Select' | 'Sub' | 'Function' | 'Property' | 'Try'
;
ContinueStatement
: 'Continue' ContinueKind StatementTerminator
;
ContinueKind
: 'Do' | 'For' | 'While'
;
StopStatement
: 'Stop' StatementTerminator
;
EndStatement
: 'End' StatementTerminator
;
ReturnStatement
: 'Return' Expression? StatementTerminator
;
Pernyataan Array-Handling
Dua pernyataan menyederhanakan bekerja dengan array: ReDim pernyataan dan Erase pernyataan.
ArrayHandlingStatement
: RedimStatement
| EraseStatement
;
Pernyataan Redim
Pernyataan ReDim membuat instans array baru.
RedimStatement
: 'ReDim' 'Preserve'? RedimClauses StatementTerminator
;
RedimClauses
: RedimClause ( Comma RedimClause )*
;
RedimClause
: Expression ArraySizeInitializationModifier
;
Setiap klausa dalam pernyataan harus diklasifikasikan sebagai variabel atau akses properti yang jenisnya adalah jenis array atau Object, dan diikuti oleh daftar batas array. Jumlah batas harus konsisten dengan jenis variabel; sejumlah batas diperbolehkan untuk Object. Pada run time, array dibuat untuk setiap ekspresi dari kiri ke kanan dengan batas yang ditentukan lalu ditetapkan ke variabel atau properti. Jika jenis variabel adalah Object, jumlah dimensi adalah jumlah dimensi yang ditentukan, dan jenis elemen array adalah Object. Jika jumlah dimensi yang diberikan tidak kompatibel dengan variabel atau properti pada waktu proses, kesalahan waktu kompilasi terjadi. Contohnya:
Module Test
Sub Main()
Dim o As Object
Dim b() As Byte
Dim i(,) As Integer
' The next two statements are equivalent.
ReDim o(10,30)
o = New Object(10, 30) {}
' The next two statements are equivalent.
ReDim b(10)
b = New Byte(10) {}
' Error: Incorrect number of dimensions.
ReDim i(10, 30, 40)
End Sub
End Module
Preserve Jika kata kunci ditentukan, maka ekspresi juga harus dapat diklasifikasikan sebagai nilai, dan ukuran baru untuk setiap dimensi kecuali untuk yang paling kanan harus sama dengan ukuran array yang ada. Nilai dalam array yang ada disalin ke dalam array baru: jika array baru lebih kecil, nilai yang ada akan dibuang; jika array baru lebih besar, elemen tambahan akan diinisialisasi ke nilai default dari jenis elemen array. Misalnya, pertimbangkan kode berikut:
Module Test
Sub Main()
Dim x(5, 5) As Integer
x(3, 3) = 3
ReDim Preserve x(5, 6)
Console.WriteLine(x(3, 3) & ", " & x(3, 6))
End Sub
End Module
Ini mencetak hasil berikut:
3, 0
Jika referensi array yang ada adalah nilai null pada waktu proses, tidak ada kesalahan yang diberikan. Selain dimensi paling kanan, jika ukuran dimensi berubah, System.ArrayTypeMismatchException akan dilemparkan.
Nota.
Preserve bukan kata yang dipesan.
Hapus Pernyataan
Pernyataan Erase menetapkan masing-masing variabel array atau properti yang ditentukan dalam pernyataan ke Nothing. Setiap ekspresi dalam pernyataan harus diklasifikasikan sebagai variabel atau akses properti yang jenisnya adalah jenis array atau Object. Contohnya:
Module Test
Sub Main()
Dim x() As Integer = New Integer(5) {}
' The following two statements are equivalent.
Erase x
x = Nothing
End Sub
End Module
EraseStatement
: 'Erase' EraseExpressions StatementTerminator
;
EraseExpressions
: Expression ( Comma Expression )*
;
Menggunakan pernyataan
Instans jenis secara otomatis dirilis oleh pengumpul sampah saat koleksi dijalankan dan tidak ada referensi langsung ke instans yang ditemukan. Jika jenis menyimpan sumber daya yang sangat berharga dan langka (seperti koneksi database atau handel file), mungkin tidak diinginkan untuk menunggu sampai pengumpulan sampah berikutnya untuk membersihkan instans tertentu dari jenis yang tidak lagi digunakan. Untuk menyediakan cara yang ringan untuk merilis sumber daya sebelum koleksi, jenis dapat mengimplementasikan System.IDisposable antarmuka. Jenis yang melakukannya mengekspos Dispose metode yang dapat dipanggil untuk memaksa sumber daya berharga segera dirilis, seperti:
Module Test
Sub Main()
Dim x As DBConnection = New DBConnection("...")
' Do some work
...
x.Dispose() ' Free the connection
End Sub
End Module
Pernyataan ini Using mengotomatiskan proses memperoleh sumber daya, menjalankan serangkaian pernyataan, lalu membuang sumber daya. Pernyataan dapat mengambil dua bentuk: dalam satu, sumber daya adalah variabel lokal yang dideklarasikan sebagai bagian dari pernyataan dan diperlakukan sebagai pernyataan deklarasi variabel lokal reguler; di yang lain, sumber daya adalah hasil dari ekspresi.
UsingStatement
: 'Using' UsingResources StatementTerminator
Block?
'End' 'Using' StatementTerminator
;
UsingResources
: VariableDeclarators
| Expression
;
Jika sumber daya adalah pernyataan deklarasi variabel lokal, maka jenis deklarasi variabel lokal harus merupakan jenis yang dapat dikonversi secara implisit ke System.IDisposable. Variabel lokal yang dideklarasikan bersifat baca-saja, tercakup ke Using blok pernyataan dan harus menyertakan penginisialisasi. Jika sumber daya adalah hasil ekspresi, ekspresi harus diklasifikasikan sebagai nilai dan harus dari jenis yang dapat dikonversi secara implisit ke System.IDisposable. Ekspresi hanya dievaluasi sekali, di awal pernyataan.
Using Blok secara implisit terkandung oleh Try pernyataan yang akhirnya memblokir memanggil metode IDisposable.Dispose pada sumber daya. Ini memastikan sumber daya dibuang bahkan ketika pengecualian dilemparkan. Akibatnya, tidak valid untuk bercabang ke blok Using dari luar blok, dan Using blok diperlakukan sebagai pernyataan tunggal untuk tujuan Resume dan Resume Next. Jika sumber daya adalah Nothing, maka tidak ada panggilan ke Dispose yang dilakukan. Dengan demikian, contohnya:
Using f As C = New C()
...
End Using
setara dengan:
Dim f As C = New C()
Try
...
Finally
If f IsNot Nothing Then
f.Dispose()
End If
End Try
Pernyataan Using yang memiliki pernyataan deklarasi variabel lokal dapat memperoleh beberapa sumber daya pada satu waktu, yang setara dengan pernyataan berlapis Using . Misalnya, Using pernyataan formulir:
Using r1 As R = New R(), r2 As R = New R()
r1.F()
r2.F()
End Using
setara dengan:
Using r1 As R = New R()
Using r2 As R = New R()
r1.F()
r2.F()
End Using
End Using
Menunggu Pernyataan
Pernyataan tunggu memiliki sintaks yang sama dengan ekspresi operator tunggu ( Operator Tunggu Bagian), hanya diizinkan dalam metode yang juga memungkinkan menunggu ekspresi, dan memiliki perilaku yang sama dengan ekspresi operator tunggu.
Namun, ini dapat diklasifikasikan sebagai nilai atau kekosongan. Nilai apa pun yang dihasilkan dari evaluasi ekspresi operator tunggu dibuang.
AwaitStatement
: AwaitOperatorExpression StatementTerminator
;
Pernyataan Hasil
Pernyataan hasil terkait dengan metode iterator, yang dijelaskan dalam Metode Iterator Bagian.
YieldStatement
: 'Yield' Expression StatementTerminator
;
Yield adalah kata yang dicadangkan jika metode penutup segera atau ekspresi lambda di mana ia muncul memiliki Iterator pengubah, dan jika Yield muncul setelah Iterator pengubah tersebut; itu tidak dilayani di tempat lain. Ini juga tidak dilayani dalam direktif praproscessor. Pernyataan hasil hanya diperbolehkan dalam isi metode atau ekspresi lambda di mana itu adalah kata yang dipesan. Dalam metode penutup segera atau lambda, pernyataan hasil mungkin tidak terjadi di dalam tubuh blok Catch atau Finally , atau di dalam tubuh SyncLock pernyataan.
Pernyataan hasil mengambil ekspresi tunggal yang harus diklasifikasikan sebagai nilai dan yang jenisnya secara implisit dapat dikonversi ke jenis variabel iterator saat ini ( Metode Iterator Bagian) dari metode iterator penutupnya.
Alur kontrol hanya pernah mencapai Yield pernyataan ketika MoveNext metode dipanggil pada objek iterator. (Ini karena instans metode iterator hanya pernah menjalankan pernyataannya karena MoveNext metode atau Dispose yang dipanggil pada objek iterator; dan Dispose metode hanya akan menjalankan kode dalam Finally blok, di mana Yield tidak diizinkan).
Yield Ketika pernyataan dijalankan, ekspresinya dievaluasi dan disimpan dalam variabel iterator saat ini dari instans metode iterator yang terkait dengan objek iterator tersebut. Nilai True dikembalikan ke pemanggil MoveNext, dan titik kontrol instans ini berhenti maju hingga pemanggilan MoveNext berikutnya pada objek iterator.
Visual Basic language spec