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.
Jenis anggota menentukan lokasi penyimpanan dan kode yang dapat dieksekusi. Mereka bisa menjadi metode, konstruktor, peristiwa, konstanta, variabel, dan properti.
Implementasi Metode Antarmuka
Metode, peristiwa, dan properti dapat menerapkan anggota antarmuka. Untuk menerapkan anggota antarmuka, deklarasi anggota menentukan Implements kata kunci dan mencantumkan satu atau beberapa anggota antarmuka.
ImplementsClause
: ( 'Implements' ImplementsList )?
;
ImplementsList
: InterfaceMemberSpecifier ( Comma InterfaceMemberSpecifier )*
;
InterfaceMemberSpecifier
: NonArrayTypeName Period IdentifierOrKeyword
;
Metode dan properti yang mengimplementasikan anggota antarmuka secara NotOverridable implisit kecuali dinyatakan sebagai MustOverride, , Overridableatau menimpa anggota lain. Ini adalah kesalahan bagi anggota yang mengimplementasikan anggota antarmuka menjadi Shared. Aksesibilitas anggota tidak berpengaruh pada kemampuannya untuk menerapkan anggota antarmuka.
Agar implementasi antarmuka valid, daftar implementasi jenis yang berisi harus memberi nama antarmuka yang berisi anggota yang kompatibel. Anggota yang kompatibel adalah anggota yang tanda tangannya cocok dengan tanda tangan anggota pelaksana. Jika antarmuka generik sedang diimplementasikan, maka argumen jenis yang disediakan dalam klausul Implements diganti ke dalam tanda tangan saat memeriksa kompatibilitas. Contohnya:
Interface I1(Of T)
Sub F(x As T)
End Interface
Class C1
Implements I1(Of Integer)
Sub F(x As Integer) Implements I1(Of Integer).F
End Sub
End Class
Class C2(Of U)
Implements I1(Of U)
Sub F(x As U) Implements I1(Of U).F
End Sub
End Class
Jika peristiwa yang dinyatakan menggunakan jenis delegasi menerapkan peristiwa antarmuka, maka peristiwa yang kompatibel adalah peristiwa yang jenis delegasinya mendasarnya adalah jenis yang sama. Jika tidak, peristiwa menggunakan jenis delegasi dari peristiwa antarmuka yang diterapkannya. Jika peristiwa semacam itu mengimplementasikan beberapa peristiwa antarmuka, semua peristiwa antarmuka harus memiliki jenis delegasi yang mendasar yang sama. Contohnya:
Interface ClickEvents
Event LeftClick(x As Integer, y As Integer)
Event RightClick(x As Integer, y As Integer)
End Interface
Class Button
Implements ClickEvents
' OK. Signatures match, delegate type = ClickEvents.LeftClickHandler.
Event LeftClick(x As Integer, y As Integer) _
Implements ClickEvents.LeftClick
' OK. Signatures match, delegate type = ClickEvents.RightClickHandler.
Event RightClick(x As Integer, y As Integer) _
Implements ClickEvents.RightClick
End Class
Class Label
Implements ClickEvents
' Error. Signatures match, but can't be both delegate types.
Event Click(x As Integer, y As Integer) _
Implements ClickEvents.LeftClick, ClickEvents.RightClick
End Class
Anggota antarmuka dalam daftar implementasi ditentukan menggunakan nama jenis, titik, dan pengidentifikasi. Nama jenis harus merupakan antarmuka dalam daftar implementasi atau antarmuka dasar antarmuka dalam daftar implementasi, dan pengidentifikasi harus menjadi anggota antarmuka yang ditentukan. Satu anggota dapat mengimplementasikan lebih dari satu anggota antarmuka yang cocok.
Interface ILeft
Sub F()
End Interface
Interface IRight
Sub F()
End Interface
Class Test
Implements ILeft, IRight
Sub F() Implements ILeft.F, IRight.F
End Sub
End Class
Jika anggota antarmuka yang diimplementasikan tidak tersedia di semua antarmuka yang diimplementasikan secara eksplisit karena beberapa pewarisan antarmuka, anggota yang menerapkan harus secara eksplisit mereferensikan antarmuka dasar tempat anggota tersedia. Misalnya, jika dan berisi anggota M, dan I3 mewarisi dari I1 dan I2, jenis yang diterapkan I3 akan mengimplementasikan I1.M dan I2.M.I2I1 Jika bayangan antarmuka mengalikan anggota yang diwariskan, jenis penerapan harus mengimplementasikan anggota yang diwariskan dan anggota yang membayanginya.
Interface ILeft
Sub F()
End Interface
Interface IRight
Sub F()
End Interface
Interface ILeftRight
Inherits ILeft, IRight
Shadows Sub F()
End Interface
Class Test
Implements ILeftRight
Sub LeftF() Implements ILeft.F
End Sub
Sub RightF() Implements IRight.F
End Sub
Sub LeftRightF() Implements ILeftRight.F
End Sub
End Class
Jika antarmuka yang berisi anggota antarmuka yang diimplementasikan bersifat umum, argumen jenis yang sama dengan antarmuka yang diterapkan harus disediakan. Contohnya:
Interface I1(Of T)
Function F() As T
End Interface
Class C1
Implements I1(Of Integer)
Implements I1(Of Double)
Function F1() As Integer Implements I1(Of Integer).F
End Function
Function F2() As Double Implements I1(Of Double).F
End Function
' Error: I1(Of String) is not implemented by C1
Function F3() As String Implements I1(Of String).F
End Function
End Class
Class C2(Of U)
Implements I1(Of U)
Function F() As U Implements I1(Of U).F
End Function
End Class
Metode
Metode berisi pernyataan program yang dapat dieksekusi.
MethodMemberDeclaration
: MethodDeclaration
| ExternalMethodDeclaration
;
InterfaceMethodMemberDeclaration
: InterfaceMethodDeclaration
;
MethodDeclaration
: SubDeclaration
| MustOverrideSubDeclaration
| FunctionDeclaration
| MustOverrideFunctionDeclaration
;
InterfaceMethodDeclaration
: InterfaceSubDeclaration
| InterfaceFunctionDeclaration
;
SubSignature
: 'Sub' Identifier TypeParameterList?
( OpenParenthesis ParameterList? CloseParenthesis )?
;
FunctionSignature
: 'Function' Identifier TypeParameterList?
( OpenParenthesis ParameterList? CloseParenthesis )?
( 'As' Attributes? TypeName )?
;
SubDeclaration
: Attributes? ProcedureModifier* SubSignature
HandlesOrImplements? LineTerminator
Block
'End' 'Sub' StatementTerminator
;
MustOverrideSubDeclaration
: Attributes? MustOverrideProcedureModifier+ SubSignature
HandlesOrImplements? StatementTerminator
;
InterfaceSubDeclaration
: Attributes? InterfaceProcedureModifier* SubSignature StatementTerminator
;
FunctionDeclaration
: Attributes? ProcedureModifier* FunctionSignature
HandlesOrImplements? LineTerminator
Block
'End' 'Function' StatementTerminator
;
MustOverrideFunctionDeclaration
: Attributes? MustOverrideProcedureModifier+ FunctionSignature
HandlesOrImplements? StatementTerminator
;
InterfaceFunctionDeclaration
: Attributes? InterfaceProcedureModifier* FunctionSignature StatementTerminator
;
ProcedureModifier
: AccessModifier | 'Shadows' | 'Shared' | 'Overridable' | 'NotOverridable' | 'Overrides'
| 'Overloads' | 'Partial' | 'Iterator' | 'Async'
;
MustOverrideProcedureModifier
: ProcedureModifier
| 'MustOverride'
;
InterfaceProcedureModifier
: 'Shadows' | 'Overloads'
;
HandlesOrImplements
: HandlesClause
| ImplementsClause
;
Metode, yang memiliki daftar parameter opsional dan nilai pengembalian opsional, dibagikan atau tidak dibagikan. Metode bersama diakses melalui kelas atau instans kelas. Metode non-bersama, juga disebut metode instans, diakses melalui instans kelas. Contoh berikut menunjukkan kelas Stack yang memiliki beberapa metode bersama (Clone dan Flip), dan beberapa metode instans (Push, Pop, dan ToString):
Public Class Stack
Public Shared Function Clone(s As Stack) As Stack
...
End Function
Public Shared Function Flip(s As Stack) As Stack
...
End Function
Public Function Pop() As Object
...
End Function
Public Sub Push(o As Object)
...
End Sub
Public Overrides Function ToString() As String
...
End Function
End Class
Module Test
Sub Main()
Dim s As Stack = New Stack()
Dim i As Integer
While i < 10
s.Push(i)
End While
Dim flipped As Stack = Stack.Flip(s)
Dim cloned As Stack = Stack.Clone(s)
Console.WriteLine("Original stack: " & s.ToString())
Console.WriteLine("Flipped stack: " & flipped.ToString())
Console.WriteLine("Cloned stack: " & cloned.ToString())
End Sub
End Module
Metode dapat kelebihan beban, yang berarti bahwa beberapa metode mungkin memiliki nama yang sama selama mereka memiliki tanda tangan unik. Tanda tangan metode terdiri dari jumlah dan jenis parameternya. Tanda tangan metode secara khusus tidak menyertakan jenis pengembalian atau pengubah parameter seperti Opsional, ByRef atau ParamArray. Contoh berikut menunjukkan kelas dengan sejumlah kelebihan beban:
Module Test
Sub F()
Console.WriteLine("F()")
End Sub
Sub F(o As Object)
Console.WriteLine("F(Object)")
End Sub
Sub F(value As Integer)
Console.WriteLine("F(Integer)")
End Sub
Sub F(a As Integer, b As Integer)
Console.WriteLine("F(Integer, Integer)")
End Sub
Sub F(values() As Integer)
Console.WriteLine("F(Integer())")
End Sub
Sub G(s As String, Optional s2 As String = 5)
Console.WriteLine("G(String, Optional String")
End Sub
Sub G(s As String)
Console.WriteLine("G(String)")
End Sub
Sub Main()
F()
F(1)
F(CType(1, Object))
F(1, 2)
F(New Integer() { 1, 2, 3 })
G("hello")
G("hello", "world")
End Sub
End Module
Output dari program adalah:
F()
F(Integer)
F(Object)
F(Integer, Integer)
F(Integer())
G(String)
G(String, Optional String)
Kelebihan beban yang hanya berbeda dalam parameter opsional dapat digunakan untuk "penerapan versi" pustaka. Misalnya, v1 pustaka mungkin menyertakan fungsi dengan parameter opsional:
Sub fopen(fileName As String, Optional accessMode as Integer = 0)
Kemudian v2 pustaka ingin menambahkan parameter opsional lain "kata sandi", dan ingin melakukannya tanpa merusak kompatibilitas sumber (sehingga aplikasi yang digunakan untuk menargetkan v1 dapat dikompilasi ulang), dan tanpa merusak kompatibilitas biner (sehingga aplikasi yang digunakan untuk mereferensikan v1 sekarang dapat mereferensikan v2 tanpa kompilasi ulang). Ini adalah bagaimana v2 akan terlihat:
Sub fopen(file As String, mode as Integer)
Sub fopen(file As String, Optional mode as Integer = 0, Optional pword As String = "")
Perhatikan bahwa parameter opsional dalam API publik tidak sesuai dengan CLS. Namun, mereka dapat dikonsumsi setidaknya oleh Visual Basic dan C#4 dan F#.
Deklarasi Metode Reguler, Asinkron, dan Iterator
Ada dua jenis metode: subroutine, yang tidak mengembalikan nilai, dan fungsi, yang melakukannya. Isi dan End konstruksi metode hanya dapat dihilangkan jika metode didefinisikan dalam antarmuka atau memiliki pengubah MustOverride . Jika tidak ada jenis pengembalian yang ditentukan pada fungsi dan semantik ketat yang digunakan, kesalahan waktu kompilasi terjadi; jika tidak, jenisnya secara Object implisit atau jenis karakter jenis metode. Domain aksesibilitas dari jenis pengembalian dan jenis parameter metode harus sama dengan atau superset domain aksesibilitas metode itu sendiri.
Metode reguler adalah metode yang tidak Async memiliki pengubahIterator. Ini mungkin subroutine atau fungsi.
Bagian Metode Reguler merinci apa yang terjadi ketika metode reguler dipanggil.
Metode iterator adalah metode dengan pengubah Iterator dan tanpa Async pengubah. Ini harus berupa fungsi, dan jenis pengembaliannya harus IEnumerator, , IEnumerableatau atau IEnumerable(Of T)IEnumerator(Of T) untuk beberapa T, dan tidak boleh memiliki ByRef parameter.
Metode Iterator Bagian merinci apa yang terjadi ketika metode iterator dipanggil.
Metode asinkron adalah metode dengan pengubah Async dan tanpa Iterator pengubah. Ini harus berupa subroutine, atau fungsi dengan jenis Task pengembalian atau Task(Of T) untuk beberapa T, dan tidak ByRef boleh memiliki parameter.
Bagian Metode Asinkron merinci apa yang terjadi ketika metode asinkron dipanggil.
Ini adalah kesalahan waktu kompilasi jika metode bukan salah satu dari tiga jenis metode ini.
Deklarasi subroutine dan fungsi istimewa karena pernyataan awal dan akhirnya harus masing-masing dimulai di awal baris logis. Selain itu, isi deklarasi non-subroutineMustOverride atau fungsi harus dimulai di awal baris logis. Contohnya:
Module Test
' Illegal: Subroutine doesn't start the line
Public x As Integer : Sub F() : End Sub
' Illegal: First statement doesn't start the line
Sub G() : Console.WriteLine("G")
End Sub
' Illegal: End Sub doesn't start the line
Sub H() : End Sub
End Module
Deklarasi Metode Eksternal
Deklarasi metode eksternal memperkenalkan metode baru yang implementasinya disediakan di luar program.
ExternalMethodDeclaration
: ExternalSubDeclaration
| ExternalFunctionDeclaration
;
ExternalSubDeclaration
: Attributes? ExternalMethodModifier* 'Declare' CharsetModifier? 'Sub'
Identifier LibraryClause AliasClause?
( OpenParenthesis ParameterList? CloseParenthesis )? StatementTerminator
;
ExternalFunctionDeclaration
: Attributes? ExternalMethodModifier* 'Declare' CharsetModifier? 'Function'
Identifier LibraryClause AliasClause?
( OpenParenthesis ParameterList? CloseParenthesis )?
( 'As' Attributes? TypeName )?
StatementTerminator
;
ExternalMethodModifier
: AccessModifier
| 'Shadows'
| 'Overloads'
;
CharsetModifier
: 'Ansi' | 'Unicode' | 'Auto'
;
LibraryClause
: 'Lib' StringLiteral
;
AliasClause
: 'Alias' StringLiteral
;
Karena deklarasi metode eksternal tidak menyediakan implementasi aktual, deklarasi tidak memiliki isi atau End konstruksi metode. Metode eksternal dibagikan secara implisit, mungkin tidak memiliki parameter jenis, dan mungkin tidak menangani peristiwa atau menerapkan anggota antarmuka. Jika tidak ada jenis pengembalian yang ditentukan pada fungsi dan semantik ketat yang digunakan, kesalahan waktu kompilasi terjadi. Jika tidak, jenisnya secara Object implisit atau jenis karakter jenis metode. Domain aksesibilitas jenis pengembalian dan jenis parameter metode eksternal harus sama dengan atau superset domain aksesibilitas dari metode eksternal itu sendiri.
Klausa pustaka dari deklarasi metode eksternal menentukan nama file eksternal yang mengimplementasikan metode . Klausa alias opsional adalah string yang menentukan ordinal numerik (diawali oleh # karakter) atau nama metode dalam file eksternal. Pengubah set karakter tunggal juga dapat ditentukan, yang mengatur kumpulan karakter yang digunakan untuk string marshal selama panggilan ke metode eksternal. Pengubah Unicode marshals semua string ke nilai Unicode, Ansi pengubah marshals semua string ke nilai ANSI, dan Auto pengubah marshals string sesuai dengan aturan .NET Framework berdasarkan nama metode, atau nama alias jika ditentukan. Jika tidak ada pengubah yang ditentukan, defaultnya adalah Ansi.
Jika Ansi atau Unicode ditentukan, maka nama metode dicari di file eksternal tanpa modifikasi. Jika Auto ditentukan, maka pencarian nama metode bergantung pada platform. Jika platform dianggap ANSI (misalnya, Windows 95, Windows 98, Windows ME), maka nama metode dicari tanpa modifikasi. Jika pencarian gagal, ditambahkan A dan pencarian mencoba lagi. Jika platform dianggap Unicode (misalnya, Windows NT, Windows 2000, Windows XP), maka ditambahkan W dan namanya dicari. Jika pencarian gagal, pencarian dicoba lagi tanpa W. Contohnya:
Module Test
' All platforms bind to "ExternSub".
Declare Ansi Sub ExternSub Lib "ExternDLL" ()
' All platforms bind to "ExternSub".
Declare Unicode Sub ExternSub Lib "ExternDLL" ()
' ANSI platforms: bind to "ExternSub" then "ExternSubA".
' Unicode platforms: bind to "ExternSubW" then "ExternSub".
Declare Auto Sub ExternSub Lib "ExternDLL" ()
End Module
Jenis data yang diteruskan ke metode eksternal dinamai sesuai dengan konvensi marshalling data .NET Framework dengan satu pengecualian. Variabel string yang diteruskan oleh nilai (yaitu, ByVal x As String) dinavigasi ke jenis OLE Automation BSTR, dan perubahan yang dilakukan pada BSTR dalam metode eksternal tercermin kembali dalam argumen string. Ini karena jenis String dalam metode eksternal dapat diubah, dan marshalling khusus ini meniadakan perilaku itu. Parameter string yang diteruskan oleh referensi (yaitu ByRef x As String) dinavigasi sebagai penunjuk ke jenis OLE Automation BSTR. Dimungkinkan untuk mengambil alih perilaku khusus ini dengan menentukan System.Runtime.InteropServices.MarshalAsAttribute atribut pada parameter .
Contoh menunjukkan penggunaan metode eksternal:
Class Path
Declare Function CreateDirectory Lib "kernel32" ( _
Name As String, sa As SecurityAttributes) As Boolean
Declare Function RemoveDirectory Lib "kernel32" ( _
Name As String) As Boolean
Declare Function GetCurrentDirectory Lib "kernel32" ( _
BufSize As Integer, Buf As String) As Integer
Declare Function SetCurrentDirectory Lib "kernel32" ( _
Name As String) As Boolean
End Class
Metode yang Dapat Diganti
Pengubah Overridable menunjukkan bahwa metode dapat diganti. Pengubah Overrides menunjukkan bahwa metode mengambil alih metode yang dapat diganti jenis dasar yang memiliki tanda tangan yang sama. Pengubah NotOverridable menunjukkan bahwa metode yang dapat diambil alih tidak dapat ditimpa lebih lanjut. Pengubah MustOverride menunjukkan bahwa metode harus ditimpa dalam kelas turunan.
Kombinasi tertentu dari pengubah ini tidak valid:
OverridabledanNotOverridablesaling eksklusif dan tidak dapat digabungkan.MustOverridemenyiratkanOverridable(dan tidak dapat menentukannya) dan tidak dapat dikombinasikan denganNotOverridable.NotOverridabletidak dapat digabungkan denganOverridableatauMustOverridedan harus dikombinasikan denganOverrides.OverridesmenyiratkanOverridable(dan tidak dapat menentukannya) dan tidak dapat dikombinasikan denganMustOverride.
Ada juga batasan tambahan pada metode yang dapat diambil alih:
Metode
MustOverridemungkin tidak menyertakan isi metode atauEndkonstruksi, mungkin tidak mengambil alih metode lain, dan hanya dapat muncul diMustInheritkelas.Jika metode menentukan
Overridesdan tidak ada metode dasar yang cocok untuk diambil alih, kesalahan waktu kompilasi terjadi. Metode penimpaan mungkin tidak menentukanShadows.Metode mungkin tidak mengambil alih metode lain jika domain aksesibilitas metode penggantian tidak sama dengan domain aksesibilitas metode yang ditimpa. Satu pengecualian adalah bahwa metode yang mengambil alih
Protected Friendmetode di rakitan lain yang tidak memilikiFriendakses harus menentukanProtected(bukanProtected Friend).Privatemetode mungkinOverridablebukan , ,NotOverridableatauMustOverride, juga tidak dapat mengambil alih metode lain.Metode dalam
NotInheritablekelas mungkin tidak dideklarasikanOverridableatauMustOverride.
Contoh berikut mengilustrasikan perbedaan antara metode yang dapat diganti dan tidak dapat diganti:
Class Base
Public Sub F()
Console.WriteLine("Base.F")
End Sub
Public Overridable Sub G()
Console.WriteLine("Base.G")
End Sub
End Class
Class Derived
Inherits Base
Public Shadows Sub F()
Console.WriteLine("Derived.F")
End Sub
Public Overrides Sub G()
Console.WriteLine("Derived.G")
End Sub
End Class
Module Test
Sub Main()
Dim d As Derived = New Derived()
Dim b As Base = d
b.F()
d.F()
b.G()
d.G()
End Sub
End Module
Dalam contoh, kelas Base memperkenalkan metode F dan Overridable metode G. Kelas Derived memperkenalkan metode Fbaru , sehingga membayangi yang diwariskan F, dan juga mengambil alih metode Gyang diwariskan . Contoh menghasilkan output berikut:
Base.F
Derived.F
Derived.G
Derived.G
Perhatikan bahwa pernyataan b.G() memanggil Derived.G, bukan Base.G. Ini karena jenis run-time instans (yaitu Derived) daripada jenis waktu kompilasi instans (yaitu Base) menentukan implementasi metode aktual untuk dipanggil.
Metode Bersama
Pengubah Shared menunjukkan metode adalah metode bersama. Metode bersama tidak beroperasi pada instans tertentu dari jenis dan dapat dipanggil langsung dari jenis daripada melalui instans tertentu dari jenis. Namun, valid untuk menggunakan instans untuk memenuhi syarat metode bersama. Tidak valid untuk merujuk ke Me, MyClass, atau MyBase dalam metode bersama. Metode bersama mungkin Overridablebukan , , NotOverridableatau MustOverride, dan mungkin tidak mengambil alih metode. Metode yang ditentukan dalam modul dan antarmuka standar mungkin tidak menentukan Shared, karena sudah secara Shared implisit.
Metode yang dideklarasikan dalam struktur atau kelas tanpa Shared pengubah adalah metode instans. Metode instans beroperasi pada instans jenis tertentu. Metode instans hanya dapat dipanggil melalui instans jenis dan dapat merujuk ke instans melalui Me ekspresi.
Contoh berikut mengilustrasikan aturan untuk mengakses anggota bersama dan instans:
Class Test
Private x As Integer
Private Shared y As Integer
Sub F()
x = 1 ' Ok, same as Me.x = 1.
y = 1 ' Ok, same as Test.y = 1.
End Sub
Shared Sub G()
x = 1 ' Error, cannot access Me.x.
y = 1 ' Ok, same as Test.y = 1.
End Sub
Shared Sub Main()
Dim t As Test = New Test()
t.x = 1 ' Ok.
t.y = 1 ' Ok.
Test.x = 1 ' Error, cannot access instance member through type.
Test.y = 1 ' Ok.
End Sub
End Class
Metode F menunjukkan bahwa dalam anggota fungsi instans, pengidentifikasi dapat digunakan untuk mengakses anggota instans dan anggota bersama. Metode G menunjukkan bahwa dalam anggota fungsi bersama, adalah kesalahan untuk mengakses anggota instans melalui pengidentifikasi. Metode Main menunjukkan bahwa dalam ekspresi akses anggota, anggota instans harus diakses melalui instans, tetapi anggota bersama dapat diakses melalui jenis atau instans.
Parameter pada Metode
Parameter adalah variabel yang dapat digunakan untuk meneruskan informasi ke dalam dan ke luar metode. Parameter metode dideklarasikan oleh daftar parameter metode, yang terdiri dari satu atau beberapa parameter yang dipisahkan oleh koma.
ParameterList
: Parameter ( Comma Parameter )*
;
Parameter
: Attributes? ParameterModifier* ParameterIdentifier ( 'As' TypeName )?
( Equals ConstantExpression )?
;
ParameterModifier
: 'ByVal' | 'ByRef' | 'Optional' | 'ParamArray'
;
ParameterIdentifier
: Identifier IdentifierModifiers
;
Jika tidak ada jenis yang ditentukan untuk parameter dan semantik ketat yang digunakan, kesalahan waktu kompilasi terjadi. Jika tidak, jenis defaultnya adalah Object atau jenis karakter jenis parameter. Bahkan di bawah semantik permisif, jika satu parameter menyertakan As klausul, semua parameter harus menentukan jenis.
Parameter ditentukan sebagai parameter nilai, referensi, opsional, atau paramarray oleh pengubah ByVal, , ByRef, Optionaldan ParamArray, masing-masing. Parameter yang tidak menentukan ByRef atau ByVal default ke ByVal.
Nama parameter dilingkupkan ke seluruh isi metode dan selalu dapat diakses publik. Pemanggilan metode membuat salinan, khusus untuk pemanggilan tersebut, parameter, dan daftar argumen pemanggilan menetapkan nilai atau referensi variabel ke parameter yang baru dibuat. Karena deklarasi metode eksternal dan deklarasi delegasi tidak memiliki isi, nama parameter duplikat diizinkan dalam daftar parameter, tetapi tidak disarankan.
Pengidentifikasi dapat diikuti oleh pengubah ? nama null untuk menunjukkan bahwa pengidentifikasi dapat diubah ke null, dan juga dengan pengubah nama array untuk menunjukkan bahwa itu adalah array. Mereka dapat digabungkan, misalnya "ByVal x?() As Integer". Tidak diperbolehkan menggunakan batas array eksplisit; juga, jika pengubah nama nullable ada, maka As klausa harus ada.
Parameter Nilai
Parameter nilai dideklarasikan dengan pengubah eksplisitByVal. Jika pengubah ByVal digunakan, pengubah ByRef mungkin tidak ditentukan. Parameter nilai muncul dengan pemanggilan anggota tempat parameter berada, dan diinisialisasi dengan nilai argumen yang diberikan dalam pemanggilan. Parameter nilai berhenti ada setelah anggota kembali.
Metode diizinkan untuk menetapkan nilai baru ke parameter nilai. Penugasan tersebut hanya memengaruhi lokasi penyimpanan lokal yang diwakili oleh parameter nilai; mereka tidak berpengaruh pada argumen aktual yang diberikan dalam pemanggilan metode.
Parameter nilai digunakan ketika nilai argumen diteruskan ke dalam metode, dan modifikasi parameter tidak memengaruhi argumen asli. Parameter nilai mengacu pada variabelnya sendiri, yang berbeda dari variabel argumen yang sesuai. Variabel ini diinisialisasi dengan menyalin nilai argumen yang sesuai. Contoh berikut menunjukkan metode F yang memiliki parameter nilai bernama p:
Module Test
Sub F(p As Integer)
Console.WriteLine("p = " & p)
p += 1
End Sub
Sub Main()
Dim a As Integer = 1
Console.WriteLine("pre: a = " & a)
F(a)
Console.WriteLine("post: a = " & a)
End Sub
End Module
Contoh menghasilkan output berikut, meskipun parameter p nilai dimodifikasi:
pre: a = 1
p = 1
post: a = 1
Parameter Referensi
Parameter referensi adalah parameter yang dideklarasikan dengan ByRef pengubah. Jika pengubah ByRef ditentukan, pengubah ByVal mungkin tidak digunakan. Parameter referensi tidak membuat lokasi penyimpanan baru. Sebagai gantinya, parameter referensi mewakili variabel yang diberikan sebagai argumen dalam metode atau pemanggilan konstruktor. Secara konseptual, nilai parameter referensi selalu sama dengan variabel yang mendasar.
Parameter referensi bertindak dalam dua mode, baik sebagai alias atau melalui copy-in copy-back.
Alias. Parameter referensi digunakan saat parameter bertindak sebagai alias untuk argumen yang disediakan penelepon. Parameter referensi tidak mendefinisikan variabel itu sendiri, melainkan mengacu pada variabel argumen yang sesuai. Modifikasi parameter referensi secara langsung dan segera berdampak pada argumen yang sesuai. Contoh berikut menunjukkan metode Swap yang memiliki dua parameter referensi:
Module Test
Sub Swap(ByRef a As Integer, ByRef b As Integer)
Dim t As Integer = a
a = b
b = t
End Sub
Sub Main()
Dim x As Integer = 1
Dim y As Integer = 2
Console.WriteLine("pre: x = " & x & ", y = " & y)
Swap(x, y)
Console.WriteLine("post: x = " & x & ", y = " & y)
End Sub
End Module
Output dari program adalah:
pre: x = 1, y = 2
post: x = 2, y = 1
Untuk pemanggilan metode Swap di kelas Main, a mewakili x, dan b mewakili y. Dengan demikian, pemanggilan memiliki efek bertukar nilai x dan y.
Dalam metode yang mengambil parameter referensi, dimungkinkan bagi beberapa nama untuk mewakili lokasi penyimpanan yang sama:
Module Test
Private s As String
Sub F(ByRef a As String, ByRef b As String)
s = "One"
a = "Two"
b = "Three"
End Sub
Sub G()
F(s, s)
End Sub
End Module
Dalam contoh pemanggilan metode F dalam meneruskan referensi ke s untuk dan ab.G Dengan demikian, untuk pemanggilan itu, nama s, , dan b semuanya merujuk ke lokasi penyimpanan yang sama, dan tiga penugasan semuanya memodifikasi variabel sinstans a.
Salin kembali. Jika jenis variabel yang diteruskan ke parameter referensi tidak kompatibel dengan jenis parameter referensi, atau jika non-variabel (misalnya properti) diteruskan sebagai argumen ke parameter referensi, atau jika pemanggilan terlambat terikat, maka variabel sementara dialokasikan dan diteruskan ke parameter referensi. Nilai yang diteruskan akan disalin ke dalam variabel sementara ini sebelum metode dipanggil dan akan disalin kembali ke variabel asli (jika ada dan jika dapat ditulis) ketika metode kembali. Dengan demikian, parameter referensi mungkin belum tentu berisi referensi ke penyimpanan yang tepat dari variabel yang diteruskan, dan perubahan apa pun pada parameter referensi mungkin tidak tercermin dalam variabel sampai metode keluar. Contohnya:
Class Base
End Class
Class Derived
Inherits Base
End Class
Module Test
Sub F(ByRef b As Base)
b = New Base()
End Sub
Property G() As Base
Get
End Get
Set
End Set
End Property
Sub Main()
Dim d As Derived
F(G) ' OK.
F(d) ' Throws System.InvalidCastException after F returns.
End Sub
End Module
Dalam kasus pemanggilan Fpertama , variabel sementara dibuat dan nilai properti G ditetapkan ke dalamnya dan diteruskan ke .F Setelah kembali dari F, nilai dalam variabel sementara ditetapkan kembali ke properti .G Dalam kasus kedua, variabel sementara lain dibuat dan nilai d ditetapkan ke dalamnya dan diteruskan ke F. Saat mengembalikan dari F, nilai dalam variabel sementara ditransmisikan kembali ke jenis variabel, Derived, dan ditetapkan ke d. Karena nilai yang diteruskan kembali tidak dapat dilemparkan ke Derived, pengecualian dilemparkan pada waktu proses.
Parameter Pilihan
Parameter opsional dideklarasikan dengan pengubah Optional . Parameter yang mengikuti parameter opsional dalam daftar parameter formal juga harus opsional; kegagalan untuk menentukan pengubah Optional pada parameter berikut akan memicu kesalahan waktu kompilasi. Parameter opsional dari beberapa jenis tipe T? nullable atau tipe T non-nullable harus menentukan ekspresi e konstanta yang akan digunakan sebagai nilai default jika tidak ada argumen yang ditentukan. Jika e mengevaluasi ke Nothing tipe Objek, maka nilai default jenis parameter akan digunakan sebagai default untuk parameter . Jika tidak, CType(e, T) harus berupa ekspresi konstanta dan diambil sebagai default untuk parameter .
Parameter opsional adalah satu-satunya situasi di mana penginisialisasi pada parameter valid. Inisialisasi selalu dilakukan sebagai bagian dari ekspresi pemanggilan, bukan dalam isi metode itu sendiri.
Module Test
Sub F(x As Integer, Optional y As Integer = 20)
Console.WriteLine("x = " & x & ", y = " & y)
End Sub
Sub Main()
F(10)
F(30,40)
End Sub
End Module
Output dari program adalah:
x = 10, y = 20
x = 30, y = 40
Parameter opsional mungkin tidak ditentukan dalam delegasi atau deklarasi peristiwa, atau dalam ekspresi lambda.
Parameter ParamArray
ParamArray parameter dideklarasikan dengan pengubah ParamArray . Jika pengubah ParamArray ada, pengubah ByVal harus ditentukan, dan tidak ada parameter lain yang dapat menggunakan pengubah ParamArray . Jenis ParamArray parameter harus berupa array satu dimensi, dan harus menjadi parameter terakhir dalam daftar parameter.
Parameter ParamArray mewakili jumlah parameter yang tidak ditentukan dari jenis ParamArray. Dalam metode itu sendiri, ParamArray parameter diperlakukan sebagai jenis yang dinyatakan dan tidak memiliki semantik khusus. Parameter ParamArray secara implisit opsional, dengan nilai default array satu dimensi kosong dari jenis ParamArray.
Argumen ParamArray izin yang akan ditentukan dalam salah satu dari dua cara dalam pemanggilan metode:
Argumen yang
ParamArraydiberikan untuk bisa berupa ekspresi tunggal dari jenis yang melebar keParamArrayjenis . Dalam hal ini,ParamArraybertindak persis seperti parameter nilai.Atau, pemanggilan dapat menentukan nol atau lebih argumen untuk
ParamArray, di mana setiap argumen adalah ekspresi jenis yang secara implisit dapat dikonversi ke jenis elemen .ParamArrayDalam hal ini, pemanggilan membuat instans jenisParamArraydengan panjang yang sesuai dengan jumlah argumen, menginisialisasi elemen instans array dengan nilai argumen yang diberikan, dan menggunakan instans array yang baru dibuat sebagai argumen aktual.
Kecuali untuk mengizinkan jumlah variabel argumen dalam pemanggilan, ParamArray tepatnya setara dengan parameter nilai dengan jenis yang sama, seperti yang diilustrasikan contoh berikut.
Module Test
Sub F(ParamArray args() As Integer)
Dim i As Integer
Console.Write("Array contains " & args.Length & " elements:")
For Each i In args
Console.Write(" " & i)
Next i
Console.WriteLine()
End Sub
Sub Main()
Dim a As Integer() = { 1, 2, 3 }
F(a)
F(10, 20, 30, 40)
F()
End Sub
End Module
Contoh menghasilkan output
Array contains 3 elements: 1 2 3
Array contains 4 elements: 10 20 30 40
Array contains 0 elements:
Pemanggilan pertama dari F hanya meneruskan array a sebagai parameter nilai. Pemanggilan F kedua secara otomatis membuat array empat elemen dengan nilai elemen yang diberikan dan meneruskan instans array tersebut sebagai parameter nilai. Demikian juga, pemanggilan F ketiga membuat array nol elemen dan meneruskan instans tersebut sebagai parameter nilai. Pemanggilan kedua dan ketiga tepatnya setara dengan penulisan:
F(New Integer() {10, 20, 30, 40})
F(New Integer() {})
ParamArray parameter mungkin tidak ditentukan dalam delegasi atau deklarasi peristiwa.
Penanganan peristiwa
Metode dapat secara deklaratif menangani peristiwa yang diangkat oleh objek dalam instans atau variabel bersama. Untuk menangani peristiwa, deklarasi metode menentukan Handles kata kunci dan mencantumkan satu atau beberapa peristiwa.
HandlesClause
: ( 'Handles' EventHandlesList )?
;
EventHandlesList
: EventMemberSpecifier ( Comma EventMemberSpecifier )*
;
EventMemberSpecifier
: Identifier Period IdentifierOrKeyword
| 'MyBase' Period IdentifierOrKeyword
| 'MyClass' Period IdentifierOrKeyword
| 'Me' Period IdentifierOrKeyword
;
Peristiwa dalam daftar ditentukan oleh dua pengidentifikasi yang dipisahkan Handles oleh titik:
Pengidentifikasi pertama harus berupa instans atau variabel bersama dalam jenis yang berisi yang menentukan
WithEventspengubah atauMyBaseatauMyClassMekata kunci; jika tidak, kesalahan waktu kompilasi terjadi. Variabel ini berisi objek yang akan meningkatkan peristiwa yang ditangani oleh metode ini.Pengidentifikasi kedua harus menentukan anggota jenis pengidentifikasi pertama. Anggota harus merupakan peristiwa, dan dapat dibagikan. Jika variabel bersama ditentukan untuk pengidentifikasi pertama, maka peristiwa harus dibagikan, atau hasil kesalahan.
Metode M handler dianggap sebagai penanganan aktivitas yang valid untuk suatu peristiwa E jika pernyataan AddHandler E, AddressOf M tersebut juga akan valid.
AddHandler Namun, tidak seperti pernyataan, penanganan aktivitas eksplisit memungkinkan penanganan peristiwa dengan metode tanpa argumen terlepas dari apakah semantik ketat sedang digunakan atau tidak:
Option Strict On
Class C1
Event E(x As Integer)
End Class
Class C2
withEvents C1 As New C1()
' Valid
Sub M1() Handles C1.E
End Sub
Sub M2()
' Invalid
AddHandler C1.E, AddressOf M1
End Sub
End Class
Satu anggota dapat menangani beberapa peristiwa yang cocok, dan beberapa metode dapat menangani satu peristiwa. Aksesibilitas metode tidak berpengaruh pada kemampuannya untuk menangani peristiwa. Contoh berikut menunjukkan bagaimana metode dapat menangani peristiwa:
Class Raiser
Event E1()
Sub Raise()
RaiseEvent E1
End Sub
End Class
Module Test
WithEvents x As Raiser
Sub E1Handler() Handles x.E1
Console.WriteLine("Raised")
End Sub
Sub Main()
x = New Raiser()
x.Raise()
x.Raise()
End Sub
End Module
Ini akan dicetak:
Raised
Raised
Jenis mewarisi semua penanganan aktivitas yang disediakan oleh jenis dasarnya. Jenis turunan tidak dapat mengubah pemetaan peristiwa yang diwarisinya dari jenis dasarnya, tetapi dapat menambahkan handler tambahan ke peristiwa.
Metode Ekstensi
Metode dapat ditambahkan ke jenis dari luar deklarasi jenis menggunakan metode ekstensi. Metode ekstensi adalah metode dengan System.Runtime.CompilerServices.ExtensionAttribute atribut yang diterapkan padanya. Mereka hanya dapat dideklarasikan dalam modul standar dan harus memiliki setidaknya satu parameter, yang menentukan jenis yang diperluas metode. Misalnya, metode ekstensi berikut memperluas jenis String:
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension> _
Sub Print(s As String)
Console.WriteLine(s)
End Sub
End Module
Nota. Meskipun Visual Basic memerlukan metode ekstensi untuk dideklarasikan dalam modul standar, bahasa lain seperti C# dapat memungkinkan mereka dideklarasikan dalam jenis jenis lain. Selama metode mengikuti konvensi lain yang diuraikan di sini dan jenis yang berisi bukan jenis generik terbuka dan tidak dapat dibuat, Visual Basic akan mengenali metode ekstensi.
Ketika metode ekstensi dipanggil, instans yang sedang dipanggilnya diteruskan ke parameter pertama. Parameter pertama tidak dapat dideklarasikan Optional atau ParamArray. Jenis apa pun, termasuk parameter jenis, dapat muncul sebagai parameter pertama dari metode ekstensi. Misalnya, metode berikut memperluas jenis Integer(), jenis apa pun yang mengimplementasikan System.Collections.Generic.IEnumerable(Of T), dan jenis apa pun sama sekali:
Imports System.Runtime.CompilerServices
Module Extensions
<Extension> _
Sub PrintArray(a() As Integer)
...
End Sub
<Extension> _
Sub PrintList(Of T)(a As IEnumerable(Of T))
...
End Sub
<Extension> _
Sub Print(Of T)(a As T)
...
End Sub
End Module
Seperti yang ditunjukkan contoh sebelumnya, antarmuka dapat diperluas. Metode ekstensi antarmuka menyediakan implementasi metode , sehingga jenis yang mengimplementasikan antarmuka yang memiliki metode ekstensi yang ditentukan di atasnya masih hanya mengimplementasikan anggota yang awalnya dideklarasikan oleh antarmuka. Contohnya:
Imports System.Runtime.CompilerServices
Interface IAction
Sub DoAction()
End Interface
Module IActionExtensions
<Extension> _
Public Sub DoAnotherAction(i As IAction)
i.DoAction()
End Sub
End Module
Class C
Implements IAction
Sub DoAction() Implements IAction.DoAction
...
End Sub
' ERROR: Cannot implement extension method IAction.DoAnotherAction
Sub DoAnotherAction() Implements IAction.DoAnotherAction
...
End Sub
End Class
Metode ekstensi juga dapat memiliki batasan jenis pada parameter jenisnya dan, sama seperti metode generik non-ekstensi, argumen jenis dapat disimpulkan:
Imports System.Runtime.CompilerServices
Module IEnumerableComparableExtensions
<Extension> _
Public Function Sort(Of T As IComparable(Of T))(i As IEnumerable(Of T)) _
As IEnumerable(Of T)
...
End Function
End Module
Metode ekstensi juga dapat diakses melalui ekspresi instans implisit dalam jenis yang diperluas:
Imports System.Runtime.CompilerServices
Class C1
Sub M1()
Me.M2()
M2()
End Sub
End Class
Module C1Extensions
<Extension>
Sub M2(c As C1)
...
End Sub
End Module
Untuk tujuan aksesibilitas, metode ekstensi juga diperlakukan sebagai anggota modul standar tempat mereka dinyatakan -- mereka tidak memiliki akses tambahan ke anggota jenis yang mereka perluas di luar akses yang mereka miliki berdasarkan konteks deklarasi mereka.
Metode ekstensi hanya tersedia ketika metode modul standar berada dalam cakupan. Jika tidak, jenis asli tidak akan tampak telah diperpanjang. Contohnya:
Imports System.Runtime.CompilerServices
Class C1
End Class
Namespace N1
Module C1Extensions
<Extension> _
Sub M1(c As C1)
...
End Sub
End Module
End Namespace
Module Test
Sub Main()
Dim c As New C1()
' Error: c has no member named "M1"
c.M1()
End Sub
End Module
Mengacu pada jenis ketika hanya metode ekstensi pada jenis yang tersedia yang masih akan menghasilkan kesalahan waktu kompilasi.
Penting untuk dicatat bahwa metode ekstensi dianggap sebagai anggota jenis dalam semua konteks di mana anggota terikat, seperti pola yang sangat ditik For Each . Contohnya:
Imports System.Runtime.CompilerServices
Class C1
End Class
Class C1Enumerator
ReadOnly Property Current() As C1
Get
...
End Get
End Property
Function MoveNext() As Boolean
...
End Function
End Class
Module C1Extensions
<Extension> _
Function GetEnumerator(c As C1) As C1Enumerator
...
End Function
End Module
Module Test
Sub Main()
Dim c As New C1()
' Valid
For Each o As Object In c
...
Next o
End Sub
End Module
Delegasi juga dapat dibuat yang merujuk ke metode ekstensi. Dengan demikian, kode:
Delegate Sub D1()
Module Test
Sub Main()
Dim s As String = "Hello, World!"
Dim d As D1
d = AddressOf s.Print
d()
End Sub
End Module
kira-kira setara dengan:
Delegate Sub D1()
Module Test
Sub Main()
Dim s As String = "Hello, World!"
Dim d As D1
d = CType([Delegate].CreateDelegate(GetType(D1), s, _
GetType(StringExtensions).GetMethod("Print")), D1)
d()
End Sub
End Module
Nota. Visual Basic biasanya menyisipkan pemeriksaan pada panggilan metode instans yang menyebabkan terjadi jika instans System.NullReferenceException yang digunakan metode adalah Nothing. Dalam kasus metode ekstensi, tidak ada cara yang efisien untuk menyisipkan pemeriksaan ini, sehingga metode ekstensi perlu secara eksplisit memeriksa Nothing.
Nota. Jenis nilai akan dikotak saat diteruskan sebagai ByVal argumen ke parameter yang ditik sebagai antarmuka. Ini menyiratkan bahwa efek samping dari metode ekstensi akan beroperasi pada salinan struktur alih-alih aslinya. Meskipun bahasa tidak membatasi argumen pertama dari metode ekstensi, disarankan agar metode ekstensi tidak digunakan untuk memperluas jenis nilai atau bahwa saat memperluas jenis nilai, parameter pertama diteruskan ByRef untuk memastikan bahwa efek samping beroperasi pada nilai asli.
Metode Parsial
Metode parsial adalah metode yang menentukan tanda tangan tetapi bukan isi metode. Isi metode dapat disediakan oleh deklarasi metode lain dengan nama dan tanda tangan yang sama, kemungkinan besar dalam deklarasi parsial lain dari jenis tersebut. Contohnya:
a.vb:
' Designer generated code
Public Partial Class MyForm
Private Partial Sub ValidateControls()
End Sub
Public Sub New()
' Initialize controls
...
ValidateControls()
End Sub
End Class
b.vb:
Public Partial Class MyForm
Public Sub ValidateControls()
' Validation logic goes here
...
End Sub
End Class
Dalam contoh ini, deklarasi parsial kelas MyForm menyatakan metode ValidateControls parsial tanpa implementasi. Konstruktor dalam deklarasi parsial memanggil metode parsial, meskipun tidak ada isi yang disediakan dalam file. Deklarasi parsial lainnya kemudian memasok implementasi MyForm metode .
Metode parsial dapat dipanggil terlepas dari apakah tubuh telah disediakan; jika tidak ada isi metode yang disediakan, panggilan diabaikan. Contohnya:
Public Class C1
Private Partial Sub M1()
End Sub
Public Sub New()
' Since no implementation is supplied, this call will not be made.
M1()
End Sub
End Class
Ekspresi apa pun yang diteruskan sebagai argumen ke panggilan metode parsial yang diabaikan juga diabaikan dan tidak dievaluasi. (Catatan. Ini berarti bahwa metode parsial adalah cara yang sangat efisien untuk menyediakan perilaku yang didefinisikan di dua jenis parsial, karena metode parsial tidak memiliki biaya jika tidak digunakan.)
Deklarasi metode parsial harus dinyatakan sebagai Private dan harus selalu menjadi subroutine tanpa pernyataan dalam tubuhnya. Metode parsial tidak dapat mengimplementasikan metode antarmuka, meskipun metode yang memasok tubuh mereka dapat.
Hanya satu metode yang dapat memasok tubuh ke metode parsial. Metode yang menyediakan tubuh ke metode parsial harus memiliki tanda tangan yang sama dengan metode parsial, batasan yang sama pada parameter jenis apa pun, pengubah deklarasi yang sama, dan parameter dan nama parameter jenis yang sama. Atribut pada metode parsial dan metode yang memasok tubuhnya digabungkan, seperti halnya atribut apa pun pada parameter metode. Demikian pula, daftar peristiwa yang ditangani metode digabungkan. Contohnya:
Class C1
Event E1()
Event E2()
Private Partial Sub S() Handles Me.E1
End Sub
' Handles both E1 and E2
Private Sub S() Handles Me.E2
...
End Sub
End Class
Konstruktor
Konstruktor adalah metode khusus yang memungkinkan kontrol atas inisialisasi. Mereka dijalankan setelah program dimulai atau ketika instans jenis dibuat. Tidak seperti anggota lain, konstruktor tidak diwariskan dan tidak memasukkan nama ke dalam ruang deklarasi jenis. Konstruktor hanya dapat dipanggil oleh ekspresi pembuatan objek atau oleh .NET Framework; mereka mungkin tidak pernah dipanggil secara langsung.
Nota. Konstruktor memiliki batasan yang sama pada penempatan baris yang dimiliki subroutine. Pernyataan awal, pernyataan akhir, dan blok semuanya harus muncul di awal baris logis.
ConstructorMemberDeclaration
: Attributes? ConstructorModifier* 'Sub' 'New'
( OpenParenthesis ParameterList? CloseParenthesis )? LineTerminator
Block?
'End' 'Sub' StatementTerminator
;
ConstructorModifier
: AccessModifier
| 'Shared'
;
Konstruktor Instans
Konstruktor instans menginisialisasi instans jenis dan dijalankan oleh .NET Framework saat instans dibuat. Daftar parameter konstruktor tunduk pada aturan yang sama dengan daftar parameter metode. Konstruktor instans dapat kelebihan beban.
Semua konstruktor dalam jenis referensi harus memanggil konstruktor lain. Jika pemanggilan eksplisit, itu harus menjadi pernyataan pertama dalam isi metode konstruktor. Pernyataan dapat memanggil konstruktor instans jenis lain -- misalnya, Me.New(...) atau MyClass.New(...) -- atau jika bukan struktur, ia dapat memanggil konstruktor instans dari jenis dasar jenis -- misalnya, MyBase.New(...). Ini tidak valid bagi konstruktor untuk memanggil dirinya sendiri. Jika konstruktor menghilangkan panggilan ke konstruktor lain, MyBase.New() itu implisit. Jika tidak ada konstruktor jenis dasar tanpa parameter, kesalahan waktu kompilasi terjadi. Karena Me tidak dianggap dibangun sampai setelah panggilan ke konstruktor kelas dasar, parameter ke pernyataan pemanggilan konstruktor tidak dapat mereferensikan Me, , MyClassatau MyBase secara implisit atau eksplisit.
Ketika pernyataan pertama konstruktor adalah formulir MyBase.New(...), konstruktor secara implisit melakukan inisialisasi yang ditentukan oleh penginisialisasi variabel variabel instans yang dideklarasikan dalam jenis. Ini sesuai dengan urutan penugasan yang dijalankan segera setelah memanggil konstruktor jenis dasar langsung. Pengurutan tersebut memastikan bahwa semua variabel instans dasar diinisialisasi oleh penginisialisasi variabel mereka sebelum pernyataan apa pun yang memiliki akses ke instans dijalankan. Contohnya:
Class A
Protected x As Integer = 1
End Class
Class B
Inherits A
Private y As Integer = x
Public Sub New()
Console.WriteLine("x = " & x & ", y = " & y)
End Sub
End Class
Kapan New B() digunakan untuk membuat instans B, output berikut diproduksi:
x = 1, y = 1
Nilainya y adalah 1 karena penginisialisasi variabel dijalankan setelah konstruktor kelas dasar dipanggil. Penginisialisasi variabel dijalankan dalam urutan tekstual yang muncul dalam deklarasi jenis.
Ketika jenis hanya Private mendeklarasikan konstruktor, tidak dimungkinkan secara umum untuk jenis lain untuk berasal dari jenis atau membuat instans jenis; satu-satunya pengecualian adalah jenis yang disarangkan dalam jenis .
Private konstruktor umumnya digunakan dalam jenis yang hanya Shared berisi anggota.
Jika jenis tidak berisi deklarasi konstruktor instans, konstruktor default secara otomatis disediakan. Konstruktor default hanya memanggil konstruktor tanpa parameter dari jenis dasar langsung. Jika jenis dasar langsung tidak memiliki konstruktor tanpa parameter yang dapat diakses, kesalahan waktu kompilasi terjadi. Jenis akses yang dideklarasikan untuk konstruktor default adalah kecuali jenisnya adalah PublicMustInherit, dalam hal ini konstruktor default adalah Protected.
Nota. Akses default untuk MustInherit konstruktor default jenis adalah Protected karena MustInherit kelas tidak dapat dibuat secara langsung. Jadi tidak ada gunanya membuat konstruktor Publicdefault .
Dalam contoh berikut, konstruktor default disediakan karena kelas tidak berisi deklarasi konstruktor:
Class Message
Dim sender As Object
Dim text As String
End Class
Dengan demikian, contohnya sama persis dengan yang berikut:
Class Message
Dim sender As Object
Dim text As String
Sub New()
End Sub
End Class
Konstruktor default yang dipancarkan ke dalam kelas yang dihasilkan perancang yang ditandai dengan atribut Microsoft.VisualBasic.CompilerServices.DesignerGeneratedAttribute akan memanggil metode Sub InitializeComponent(), jika ada, setelah panggilan ke konstruktor dasar. (Catatan. Ini memungkinkan perancang membuat file, seperti yang dibuat oleh desainer WinForms, untuk menghilangkan konstruktor dalam file desainer. Ini memungkinkan programmer untuk menentukannya sendiri, jika mereka memilih.)
Konstruktor Bersama
Konstruktor bersama menginisialisasi variabel bersama jenis; mereka dijalankan setelah program mulai dieksekusi, tetapi sebelum referensi apa pun kepada anggota jenis. Konstruktor bersama menentukan Shared pengubah, kecuali jika berada dalam modul standar dalam hal Shared ini pengubah tersirat.
Tidak seperti konstruktor instans, konstruktor bersama memiliki akses publik implisit, tidak memiliki parameter, dan mungkin tidak memanggil konstruktor lain. Sebelum pernyataan pertama dalam konstruktor bersama, konstruktor bersama secara implisit melakukan inisialisasi yang ditentukan oleh inisialisasi variabel dari variabel bersama yang dideklarasikan dalam jenis . Ini sesuai dengan rangkaian penugasan yang dilaksanakan segera setelah masuk ke konstruktor. Penginisialisasi variabel dijalankan dalam urutan tekstual yang muncul dalam deklarasi jenis.
Contoh berikut menunjukkan Employee kelas dengan konstruktor bersama yang menginisialisasi variabel bersama:
Imports System.Data
Class Employee
Private Shared ds As DataSet
Shared Sub New()
ds = New DataSet()
End Sub
Public Name As String
Public Salary As Decimal
End Class
Konstruktor bersama terpisah ada untuk setiap jenis generik tertutup. Karena konstruktor bersama dijalankan tepat sekali untuk setiap jenis tertutup, ini adalah tempat yang nyaman untuk menerapkan pemeriksaan run-time pada parameter jenis yang tidak dapat diperiksa pada waktu kompilasi melalui batasan. Misalnya, jenis berikut menggunakan konstruktor bersama untuk memberlakukan bahwa parameter jenis adalah Integer atau Double:
Class EnumHolder(Of T)
Shared Sub New()
If Not GetType(T).IsEnum() Then
Throw New ArgumentException("T must be an enumerated type.")
End If
End Sub
End Class
Tepat ketika konstruktor bersama dijalankan sebagian besar bergantung pada implementasi, meskipun beberapa jaminan diberikan jika konstruktor bersama secara eksplisit ditentukan:
Konstruktor bersama dijalankan sebelum akses pertama ke bidang statis jenis apa pun.
Konstruktor bersama dijalankan sebelum pemanggilan pertama dari metode statis jenis apa pun.
Konstruktor bersama dijalankan sebelum pemanggilan pertama konstruktor apa pun untuk jenis tersebut.
Jaminan di atas tidak berlaku dalam situasi di mana konstruktor bersama dibuat secara implisit untuk penginisialisasi bersama. Output dari contoh berikut tidak pasti, karena urutan pemuatan yang tepat dan oleh karena itu eksekusi konstruktor bersama tidak ditentukan:
Module Test
Sub Main()
A.F()
B.F()
End Sub
End Module
Class A
Shared Sub New()
Console.WriteLine("Init A")
End Sub
Public Shared Sub F()
Console.WriteLine("A.F")
End Sub
End Class
Class B
Shared Sub New()
Console.WriteLine("Init B")
End Sub
Public Shared Sub F()
Console.WriteLine("B.F")
End Sub
End Class
Outputnya bisa berupa salah satu dari berikut ini:
Init A
A.F
Init B
B.F
atau
Init B
Init A
A.F
B.F
Sebaliknya, contoh berikut menghasilkan output yang dapat diprediksi. Perhatikan bahwa Shared konstruktor untuk kelas A tidak pernah dijalankan, meskipun kelas B berasal darinya:
Module Test
Sub Main()
B.G()
End Sub
End Module
Class A
Shared Sub New()
Console.WriteLine("Init A")
End Sub
End Class
Class B
Inherits A
Shared Sub New()
Console.WriteLine("Init B")
End Sub
Public Shared Sub G()
Console.WriteLine("B.G")
End Sub
End Class
Outputnya adalah:
Init B
B.G
Dimungkinkan juga untuk membangun dependensi melingkar yang memungkinkan Shared variabel dengan penginisialisasi variabel diamati dalam status nilai defaultnya, seperti dalam contoh berikut:
Class A
Public Shared X As Integer = B.Y + 1
End Class
Class B
Public Shared Y As Integer = A.X + 1
Shared Sub Main()
Console.WriteLine("X = " & A.X & ", Y = " & B.Y)
End Sub
End Class
Ini menghasilkan output:
X = 1, Y = 2
Untuk menjalankan Main metode , sistem terlebih dahulu memuat kelas B.
Shared Konstruktor kelas B melanjutkan untuk menghitung nilai Yawal , yang secara rekursif menyebabkan kelas A dimuat karena nilai A.X direferensikan.
Shared Konstruktor kelas A pada gilirannya melanjutkan untuk menghitung nilai Xawal , dan dalam melakukannya mengambil nilai default , Yyaitu nol.
A.X dengan demikian diinisialisasi ke 1. Proses pemuatan A kemudian selesai, kembali ke perhitungan nilai Yawal , yang hasilnya menjadi 2.
Main Jika metode tersebut berada di kelas A, contohnya akan menghasilkan output berikut:
X = 2, Y = 1
Hindari referensi melingkar dalam Shared penginisialisasi variabel karena umumnya tidak mungkin untuk menentukan urutan kelas yang berisi referensi tersebut dimuat.
Peristiwa
Peristiwa digunakan untuk memberi tahu kode tentang kemunculan tertentu. Deklarasi peristiwa terdiri dari pengidentifikasi, jenis delegasi atau daftar parameter, dan klausa opsional Implements .
EventMemberDeclaration
: RegularEventMemberDeclaration
| CustomEventMemberDeclaration
;
RegularEventMemberDeclaration
: Attributes? EventModifiers* 'Event'
Identifier ParametersOrType ImplementsClause? StatementTerminator
;
InterfaceEventMemberDeclaration
: Attributes? InterfaceEventModifiers* 'Event'
Identifier ParametersOrType StatementTerminator
;
ParametersOrType
: ( OpenParenthesis ParameterList? CloseParenthesis )?
| 'As' NonArrayTypeName
;
EventModifiers
: AccessModifier
| 'Shadows'
| 'Shared'
;
InterfaceEventModifiers
: 'Shadows'
;
Jika jenis delegasi ditentukan, jenis delegasi mungkin tidak memiliki jenis pengembalian. Jika daftar parameter ditentukan, daftar parameter mungkin tidak berisi Optional atau ParamArray parameter. Domain aksesibilitas jenis parameter dan/atau jenis delegasi harus sama dengan, atau superset, domain aksesibilitas peristiwa itu sendiri. Peristiwa dapat dibagikan dengan menentukan pengubah Shared .
Selain nama anggota yang ditambahkan ke ruang deklarasi jenis, deklarasi peristiwa secara implisit mendeklarasikan beberapa anggota lain. Diberi peristiwa bernama X, anggota berikut ditambahkan ke ruang deklarasi:
Jika bentuk deklarasi adalah deklarasi metode, kelas delegasi berlapis bernama
XEventHandlerdiperkenalkan. Kelas delegasi berlapis cocok dengan deklarasi metode dan memiliki aksesibilitas yang sama dengan peristiwa. Atribut dalam daftar parameter berlaku untuk parameter kelas delegasi.PrivateVariabel instans yang di ketik sebagai delegasi, bernamaXEvent.Dua metode bernama
add_Xdanremove_Xyang tidak dapat dipanggil, ditimpa, atau kelebihan beban.
Jika jenis mencoba mendeklarasikan nama yang cocok dengan salah satu nama di atas, kesalahan waktu kompilasi akan dihasilkan, dan implisit add_X dan remove_X deklarasi diabaikan untuk tujuan pengikatan nama. Tidak dimungkinkan untuk mengambil alih atau membebani salah satu anggota yang diperkenalkan, meskipun dimungkinkan untuk membayangi mereka dalam jenis turunan. Misalnya, deklarasi kelas
Class Raiser
Public Event Constructed(i As Integer)
End Class
setara dengan deklarasi berikut
Class Raiser
Public Delegate Sub ConstructedEventHandler(i As Integer)
Protected ConstructedEvent As ConstructedEventHandler
Public Sub add_Constructed(d As ConstructedEventHandler)
ConstructedEvent = _
CType( _
[Delegate].Combine(ConstructedEvent, d), _
Raiser.ConstructedEventHandler)
End Sub
Public Sub remove_Constructed(d As ConstructedEventHandler)
ConstructedEvent = _
CType( _
[Delegate].Remove(ConstructedEvent, d), _
Raiser.ConstructedEventHandler)
End Sub
End Class
Mendeklarasikan peristiwa tanpa menentukan jenis delegasi adalah sintaks yang paling sederhana dan paling ringkas, tetapi memiliki kerugian mendeklarasikan jenis delegasi baru untuk setiap peristiwa. Misalnya, dalam contoh berikut, tiga jenis delegasi tersembunyi dibuat, meskipun ketiga peristiwa memiliki daftar parameter yang sama:
Public Class Button
Public Event Click(sender As Object, e As EventArgs)
Public Event DoubleClick(sender As Object, e As EventArgs)
Public Event RightClick(sender As Object, e As EventArgs)
End Class
Dalam contoh berikut, peristiwa hanya menggunakan delegasi yang sama, EventHandler:
Public Delegate Sub EventHandler(sender As Object, e As EventArgs)
Public Class Button
Public Event Click As EventHandler
Public Event DoubleClick As EventHandler
Public Event RightClick As EventHandler
End Class
Peristiwa dapat ditangani dengan salah satu dari dua cara: secara statis atau dinamis. Penanganan peristiwa secara statis lebih sederhana dan hanya memerlukan variabel dan Handles klausaWithEvents. Dalam contoh berikut, kelas Form1 secara statis menangani peristiwa Click objek Button:
Public Class Form1
Public WithEvents Button1 As New Button()
Public Sub Button1_Click(sender As Object, e As EventArgs) _
Handles Button1.Click
Console.WriteLine("Button1 was clicked!")
End Sub
End Class
Penanganan peristiwa secara dinamis lebih kompleks karena peristiwa harus secara eksplisit terhubung dan terputus ke dalam kode. Pernyataan AddHandler menambahkan handler untuk suatu peristiwa, dan pernyataan RemoveHandler menghapus handler untuk suatu peristiwa. Contoh berikutnya menunjukkan kelas Form1 yang ditambahkan Button1_Click sebagai penanganan aktivitas untuk Button1Click peristiwa:
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
Dalam metode Disconnect, penanganan aktivitas dihapus.
Peristiwa Kustom
Seperti yang dibahas di bagian sebelumnya, deklarasi peristiwa secara implisit menentukan bidang, add_ metode, dan remove_ metode yang digunakan untuk melacak penanganan aktivitas. Namun, dalam beberapa situasi, mungkin diinginkan untuk menyediakan kode kustom untuk melacak penanganan aktivitas. Misalnya, jika kelas mendefinisikan empat puluh peristiwa yang hanya beberapa akan pernah ditangani, menggunakan tabel hash alih-alih empat puluh bidang untuk melacak handler untuk setiap peristiwa mungkin lebih efisien.
Peristiwa kustom memungkinkan add_X metode dan remove_X didefinisikan secara eksplisit, yang memungkinkan penyimpanan kustom untuk penanganan aktivitas.
Peristiwa kustom dideklarasikan dengan cara yang sama seperti peristiwa yang menentukan jenis delegasi dideklarasikan, dengan pengecualian bahwa kata kunci Custom harus mendahului Event kata kunci. Deklarasi peristiwa kustom berisi tiga deklarasi: AddHandler deklarasi, deklarasi, RemoveHandler dan RaiseEvent deklarasi. Tidak ada deklarasi yang dapat memiliki pengubah, meskipun mereka dapat memiliki atribut.
CustomEventMemberDeclaration
: Attributes? EventModifiers* 'Custom' 'Event'
Identifier 'As' TypeName ImplementsClause? StatementTerminator
EventAccessorDeclaration+
'End' 'Event' StatementTerminator
;
EventAccessorDeclaration
: AddHandlerDeclaration
| RemoveHandlerDeclaration
| RaiseEventDeclaration
;
AddHandlerDeclaration
: Attributes? 'AddHandler'
OpenParenthesis ParameterList CloseParenthesis LineTerminator
Block?
'End' 'AddHandler' StatementTerminator
;
RemoveHandlerDeclaration
: Attributes? 'RemoveHandler'
OpenParenthesis ParameterList CloseParenthesis LineTerminator
Block?
'End' 'RemoveHandler' StatementTerminator
;
RaiseEventDeclaration
: Attributes? 'RaiseEvent'
OpenParenthesis ParameterList CloseParenthesis LineTerminator
Block?
'End' 'RaiseEvent' StatementTerminator
;
Contohnya:
Class Test
Private Handlers As EventHandler
Public Custom Event TestEvent As EventHandler
AddHandler(value As EventHandler)
Handlers = CType([Delegate].Combine(Handlers, value), _
EventHandler)
End AddHandler
RemoveHandler(value as EventHandler)
Handlers = CType([Delegate].Remove(Handlers, value), _
EventHandler)
End RemoveHandler
RaiseEvent(sender As Object, e As EventArgs)
Dim TempHandlers As EventHandler = Handlers
If TempHandlers IsNot Nothing Then
TempHandlers(sender, e)
End If
End RaiseEvent
End Event
End Class
AddHandler Deklarasi dan RemoveHandler mengambil satu ByVal parameter, yang harus dari jenis delegasi peristiwa. Ketika pernyataan AddHandler atau RemoveHandler dijalankan (atau Handles klausul secara otomatis menangani peristiwa), deklarasi yang sesuai akan dipanggil.
RaiseEvent Deklarasi mengambil parameter yang sama dengan delegasi peristiwa dan akan dipanggil saat RaiseEvent pernyataan dijalankan. Semua deklarasi harus disediakan dan dianggap sebagai subroutine.
Perhatikan bahwa AddHandler, RemoveHandler dan RaiseEvent deklarasi memiliki batasan yang sama pada penempatan baris yang dimiliki sub-rutin. Pernyataan awal, pernyataan akhir, dan blok semuanya harus muncul di awal baris logis.
Selain nama anggota yang ditambahkan ke ruang deklarasi jenis, deklarasi peristiwa kustom secara implisit mendeklarasikan beberapa anggota lain. Diberi peristiwa bernama X, anggota berikut ditambahkan ke ruang deklarasi:
Metode bernama
add_X, sesuai denganAddHandlerdeklarasi.Metode bernama
remove_X, sesuai denganRemoveHandlerdeklarasi.Metode bernama
fire_X, sesuai denganRaiseEventdeklarasi.
Jika jenis mencoba mendeklarasikan nama yang cocok dengan salah satu nama di atas, kesalahan waktu kompilasi akan dihasilkan, dan deklarasi implisit semuanya diabaikan untuk tujuan pengikatan nama. Tidak dimungkinkan untuk mengambil alih atau membebani salah satu anggota yang diperkenalkan, meskipun dimungkinkan untuk membayangi mereka dalam jenis turunan.
Nota.
Custom bukan kata yang dipesan.
Peristiwa kustom di rakitan WinRT
Pada Microsoft Visual Basic 11.0, peristiwa yang dideklarasikan dalam file yang dikompilasi dengan /target:winmdobj, atau dideklarasikan dalam antarmuka dalam file seperti itu dan kemudian diimplementasikan di tempat lain, diperlakukan sedikit berbeda.
Alat eksternal yang digunakan untuk membangun winmd biasanya hanya akan mengizinkan jenis delegasi tertentu seperti
System.EventHandler(Of T)atauSystem.TypedEventHandle(Of T, U), dan akan melarang orang lain.Bidang
XEventmemiliki jenisSystem.Runtime.InteropServices.WindowsRuntime.EventRegistrationTokenTable(Of T)di manaTadalah jenis delegasi.Aksesor AddHandler mengembalikan
System.Runtime.InteropServices.WindowsRuntime.EventRegistrationToken, dan aksesor RemoveHandler mengambil satu parameter dengan jenis yang sama.
Berikut adalah contoh peristiwa kustom seperti itu.
Imports System.Runtime.InteropServices.WindowsRuntime
Public NotInheritable Class ClassInWinMD
Private XEvent As EventRegistrationTokenTable(Of EventHandler(Of Integer))
Public Custom Event X As EventHandler(Of Integer)
AddHandler(handler As EventHandler(Of Integer))
Return EventRegistrationTokenTable(Of EventHandler(Of Integer)).
GetOrCreateEventRegistrationTokenTable(XEvent).
AddEventHandler(handler)
End AddHandler
RemoveHandler(token As EventRegistrationToken)
EventRegistrationTokenTable(Of EventHandler(Of Integer)).
GetOrCreateEventRegistrationTokenTable(XEvent).
RemoveEventHandler(token)
End RemoveHandler
RaiseEvent(sender As Object, i As Integer)
Dim table = EventRegistrationTokenTable(Of EventHandler(Of Integer)).
GetOrCreateEventRegistrationTokenTable(XEvent).
InvocationList
If table IsNot Nothing Then table(sender, i)
End RaiseEvent
End Event
End Class
Konstanta
Konstanta adalah nilai konstanta yang merupakan anggota dari jenis.
ConstantMemberDeclaration
: Attributes? ConstantModifier* 'Const' ConstantDeclarators StatementTerminator
;
ConstantModifier
: AccessModifier
| 'Shadows'
;
ConstantDeclarators
: ConstantDeclarator ( Comma ConstantDeclarator )*
;
ConstantDeclarator
: Identifier ( 'As' TypeName )? Equals ConstantExpression StatementTerminator
;
Konstanta dibagikan secara implisit. Jika deklarasi berisi As klausa, klausul menentukan jenis anggota yang diperkenalkan oleh deklarasi. Jika jenis dihilangkan, maka jenis konstanta disimpulkan. Jenis konstanta mungkin hanya jenis primitif atau Object. Jika konstanta di ketik sebagai Object dan tidak ada karakter jenis, jenis konstanta nyata akan menjadi jenis ekspresi konstanta. Jika tidak, jenis konstanta adalah jenis karakter jenis konstanta.
Contoh berikut menunjukkan kelas bernama Constants yang memiliki dua konstanta publik:
Class Constants
Public Const A As Integer = 1
Public Const B As Integer = A + 1
End Class
Konstanta dapat diakses melalui kelas, seperti dalam contoh berikut, yang mencetak nilai Constants.A dan Constants.B.
Module Test
Sub Main()
Console.WriteLine(Constants.A & ", " & Constants.B)
End Sub
End Module
Deklarasi konstanta yang menyatakan beberapa konstanta setara dengan beberapa deklarasi konstanta tunggal. Contoh berikut mendeklarasikan tiga konstanta dalam satu pernyataan deklarasi.
Class A
Protected Const x As Integer = 1, y As Long = 2, z As Short = 3
End Class
Deklarasi ini setara dengan yang berikut:
Class A
Protected Const x As Integer = 1
Protected Const y As Long = 2
Protected Const z As Short = 3
End Class
Domain aksesibilitas jenis konstanta harus sama dengan atau superset domain aksesibilitas konstanta itu sendiri. Ekspresi konstanta harus menghasilkan nilai dari jenis konstanta atau jenis yang secara implisit dapat dikonversi ke jenis konstanta. Ekspresi konstanta mungkin tidak melingkar; artinya, konstanta mungkin tidak didefinisikan dalam hal dirinya sendiri.
Pengkompilasi secara otomatis mengevaluasi deklarasi konstanta dalam urutan yang sesuai. Dalam contoh berikut, kompilator terlebih dahulu mengevaluasi Y, lalu Z, dan akhirnya X, masing-masing menghasilkan nilai 10, 11, dan 12.
Class A
Public Const X As Integer = B.Z + 1
Public Const Y As Integer = 10
End Class
Class B
Public Const Z As Integer = A.Y + 1
End Class
Ketika nama simbolis untuk nilai konstanta diinginkan, tetapi jenis nilai tidak diizinkan dalam deklarasi konstanta atau ketika nilai tidak dapat dihitung pada waktu kompilasi oleh ekspresi konstanta, variabel baca-saja dapat digunakan sebagai gantinya.
Instans dan Variabel Bersama
Instans atau variabel bersama adalah anggota dari jenis yang dapat menyimpan informasi.
VariableMemberDeclaration
: Attributes? VariableModifier+ VariableDeclarators StatementTerminator
;
VariableModifier
: AccessModifier
| 'Shadows'
| 'Shared'
| 'ReadOnly'
| 'WithEvents'
| 'Dim'
;
VariableDeclarators
: VariableDeclarator ( Comma VariableDeclarator )*
;
VariableDeclarator
: VariableIdentifiers 'As' ObjectCreationExpression
| VariableIdentifiers ( 'As' TypeName )? ( Equals Expression )?
;
VariableIdentifiers
: VariableIdentifier ( Comma VariableIdentifier )*
;
VariableIdentifier
: Identifier IdentifierModifiers
;
Pengubah Dim harus ditentukan jika tidak ada pengubah yang ditentukan, tetapi dapat dihilangkan sebaliknya. Satu deklarasi variabel dapat mencakup beberapa deklarator variabel; setiap deklarator variabel memperkenalkan instans baru atau anggota bersama.
Jika penginisialisasi ditentukan, hanya satu instans atau variabel bersama yang dapat dideklarasikan oleh deklarator variabel:
Class Test
Dim a, b, c, d As Integer = 10 ' Invalid: multiple initialization
End Class
Pembatasan ini tidak berlaku untuk penginisialisasi objek:
Class Test
Dim a, b, c, d As New Collection() ' OK
End Class
Variabel yang dideklarasikan dengan pengubah Shared adalah variabel bersama. Variabel bersama mengidentifikasi persis satu lokasi penyimpanan terlepas dari jumlah instans jenis yang dibuat. Variabel bersama muncul ketika program mulai dieksekusi, dan berhenti ada ketika program berakhir.
Variabel bersama hanya dibagikan di antara instans jenis generik tertutup tertentu. Misalnya, program:
Class C(Of V)
Shared InstanceCount As Integer = 0
Public Sub New()
InstanceCount += 1
End Sub
Public Shared ReadOnly Property Count() As Integer
Get
Return InstanceCount
End Get
End Property
End Class
Class Application
Shared Sub Main()
Dim x1 As New C(Of Integer)()
Console.WriteLine(C(Of Integer).Count)
Dim x2 As New C(Of Double)()
Console.WriteLine(C(Of Integer).Count)
Dim x3 As New C(Of Integer)()
Console.WriteLine(C(Of Integer).Count)
End Sub
End Class
Cetak keluar:
1
1
2
Variabel yang dideklarasikan tanpa pengubah Shared disebut variabel instans. Setiap instans kelas berisi salinan terpisah dari semua variabel instans kelas. Variabel instans dari jenis referensi muncul ketika instans baru dari jenis tersebut dibuat, dan berhenti ada ketika tidak ada referensi ke instans tersebut Finalize dan metode telah dijalankan. Variabel instans dari jenis nilai memiliki masa pakai yang sama persis dengan variabel tempatnya berada. Dengan kata lain, ketika variabel jenis nilai muncul atau berhenti ada, begitu juga variabel instans dari jenis nilai.
Jika deklarator berisi As klausa, klausul menentukan jenis anggota yang diperkenalkan oleh deklarasi. Jika jenis dihilangkan dan semantik ketat sedang digunakan, kesalahan waktu kompilasi terjadi. Jika tidak, jenis anggota secara Object implisit atau jenis karakter jenis anggota.
Nota. Tidak ada ambiguitas dalam sintaks: jika deklarator menghilangkan jenis, itu akan selalu menggunakan jenis deklarator berikut.
Domain aksesibilitas instans atau jenis variabel bersama atau jenis elemen array harus sama dengan atau superset domain aksesibilitas instans atau variabel bersama itu sendiri.
Contoh berikut menunjukkan Color kelas yang memiliki variabel instans internal bernama redPart, , greenPartdan bluePart:
Class Color
Friend redPart As Short
Friend bluePart As Short
Friend greenPart As Short
Public Sub New(red As Short, blue As Short, green As Short)
redPart = red
bluePart = blue
greenPart = green
End Sub
End Class
Variabel Read-Only
Ketika instans atau deklarasi variabel bersama menyertakan ReadOnly pengubah, penugasan ke variabel yang diperkenalkan oleh deklarasi hanya dapat terjadi sebagai bagian dari deklarasi atau dalam konstruktor di kelas yang sama. Secara khusus, penugasan ke instans baca-saja atau variabel bersama hanya diizinkan dalam situasi berikut:
Dalam deklarasi variabel yang memperkenalkan instans atau variabel bersama (dengan menyertakan penginisialisasi variabel dalam deklarasi).
Untuk variabel instans, dalam konstruktor instans kelas yang berisi deklarasi variabel. Variabel instans hanya dapat diakses dengan cara yang tidak memenuhi syarat atau melalui
MeatauMyClass.Untuk variabel bersama, di konstruktor bersama kelas yang berisi deklarasi variabel bersama.
Variabel baca-saja bersama berguna ketika nama simbolis untuk nilai konstanta diinginkan, tetapi ketika jenis nilai tidak diizinkan dalam deklarasi konstanta, atau ketika nilai tidak dapat dihitung pada waktu kompilasi oleh ekspresi konstanta.
Contoh aplikasi pertama seperti itu mengikuti, di mana variabel bersama warna dinyatakan ReadOnly untuk mencegahnya diubah oleh program lain:
Class Color
Friend redPart As Short
Friend bluePart As Short
Friend greenPart As Short
Public Sub New(red As Short, blue As Short, green As Short)
redPart = red
bluePart = blue
greenPart = green
End Sub
Public Shared ReadOnly Red As Color = New Color(&HFF, 0, 0)
Public Shared ReadOnly Blue As Color = New Color(0, &HFF, 0)
Public Shared ReadOnly Green As Color = New Color(0, 0, &HFF)
Public Shared ReadOnly White As Color = New Color(&HFF, &HFF, &HFF)
End Class
Konstanta dan variabel bersama baca-saja memiliki semantik yang berbeda. Saat ekspresi mereferensikan konstanta, nilai konstanta diperoleh pada waktu kompilasi, tetapi ketika ekspresi mereferensikan variabel bersama baca-saja, nilai variabel bersama tidak diperoleh hingga run time. Pertimbangkan aplikasi berikut, yang terdiri dari dua program terpisah.
file1.vb:
Namespace Program1
Public Class Utils
Public Shared ReadOnly X As Integer = 1
End Class
End Namespace
file2.vb:
Namespace Program2
Module Test
Sub Main()
Console.WriteLine(Program1.Utils.X)
End Sub
End Module
End Namespace
Namespace Program1 layanan dan Program2 menunjukkan dua program yang dikompilasi secara terpisah. Karena variabel Program1.Utils.X dinyatakan sebagai Shared ReadOnly, nilai output oleh Console.WriteLine pernyataan tidak diketahui pada waktu kompilasi, melainkan diperoleh pada waktu proses. Dengan demikian, jika nilai X diubah dan Program1 dikompresi ulang, Console.WriteLine pernyataan akan menghasilkan nilai baru meskipun Program2 tidak dikompresi ulang. Namun, jika X telah menjadi konstanta, nilai X akan diperoleh pada saat Program2 itu dikompilasi, dan akan tetap tidak terpengaruh oleh perubahan dalam Program1 sampai Program2 dikompilasi ulang.
Variabel WithEvents
Jenis dapat menyatakan bahwa ia menangani beberapa set peristiwa yang dinaikkan oleh salah satu instans atau variabel bersamanya dengan mendeklarasikan instans atau variabel bersama yang meningkatkan peristiwa dengan pengubah WithEvents . Contohnya:
Class Raiser
Public Event E1()
Public Sub Raise()
RaiseEvent E1
End Sub
End Class
Module Test
Private WithEvents x As Raiser
Private Sub E1Handler() Handles x.E1
Console.WriteLine("Raised")
End Sub
Public Sub Main()
x = New Raiser()
End Sub
End Module
Dalam contoh ini, metode E1Handler menangani peristiwa E1 yang dinaikkan oleh instans jenis Raiser yang disimpan dalam variabel xinstans .
Pengubah WithEvents menyebabkan variabel diganti namanya dengan garis bawah depan dan diganti dengan properti dengan nama yang sama yang melakukan hookup peristiwa. Misalnya, jika nama variabel adalah F, itu diganti namanya menjadi _F dan properti F dideklarasikan secara implisit. Jika ada tabrakan antara nama baru variabel dan deklarasi lain, kesalahan waktu kompilasi akan dilaporkan. Atribut apa pun yang diterapkan ke variabel dibawa ke variabel yang diganti namanya.
Properti implisit yang WithEvents dibuat oleh deklarasi mengurus kait dan melepaskan pengatur aktivitas yang relevan. Ketika nilai ditetapkan ke variabel, properti pertama-tama memanggil metode untuk peristiwa pada instans remove yang saat ini berada dalam variabel (melepaskan penangan aktivitas yang ada, jika ada). Selanjutnya tugas dibuat, dan properti memanggil metode untuk peristiwa pada instans add baru dalam variabel (menghubungkan penanganan aktivitas baru). Kode berikut setara dengan kode di atas untuk modul Teststandar :
Module Test
Private _x As Raiser
Public Property x() As Raiser
Get
Return _x
End Get
Set (Value As Raiser)
' Unhook any existing handlers.
If _x IsNot Nothing Then
RemoveHandler _x.E1, AddressOf E1Handler
End If
' Change value.
_x = Value
' Hook-up new handlers.
If _x IsNot Nothing Then
AddHandler _x.E1, AddressOf E1Handler
End If
End Set
End Property
Sub E1Handler()
Console.WriteLine("Raised")
End Sub
Sub Main()
x = New Raiser()
End Sub
End Module
Tidak valid untuk mendeklarasikan instans atau variabel bersama seolah-olah WithEvents variabel diketik sebagai struktur. Selain itu, WithEvents mungkin tidak ditentukan dalam struktur, dan WithEvents dan ReadOnly tidak dapat digabungkan.
Penginisialisasi Variabel
Deklarasi variabel instans dan bersama di kelas dan deklarasi variabel instans (tetapi bukan deklarasi variabel bersama) dalam struktur dapat mencakup penginisialisasi variabel. Untuk Shared variabel, penginisialisasi variabel sesuai dengan pernyataan penugasan yang dijalankan setelah program dimulai, tetapi sebelum Shared variabel pertama kali direferensikan. Untuk variabel instans, penginisialisasi variabel sesuai dengan pernyataan penugasan yang dijalankan saat instans kelas dibuat. Struktur tidak dapat memiliki penginisialisasi variabel instans karena konstruktor tanpa parameternya tidak dapat dimodifikasi.
Pertimbangkan contoh berikut:
Class Test
Public Shared x As Double = Math.Sqrt(2.0)
Public i As Integer = 100
Public s As String = "Hello"
End Class
Module TestModule
Sub Main()
Dim a As New Test()
Console.WriteLine("x = " & Test.x & ", i = " & a.i & ", s = " & a.s)
End Sub
End Module
Contoh menghasilkan output berikut:
x = 1.4142135623731, i = 100, s = Hello
Penugasan terjadi x ketika kelas dimuat, dan penugasan ke i dan s terjadi saat instans baru kelas dibuat.
Berguna untuk menganggap penginisialisasi variabel sebagai pernyataan penugasan yang secara otomatis dimasukkan dalam blok konstruktor jenis. Contoh berikut berisi beberapa penginisialisasi variabel instans.
Class A
Private x As Integer = 1
Private y As Integer = -1
Private count As Integer
Public Sub New()
count = 0
End Sub
Public Sub New(n As Integer)
count = n
End Sub
End Class
Class B
Inherits A
Private sqrt2 As Double = Math.Sqrt(2.0)
Private items As ArrayList = New ArrayList(100)
Private max As Integer
Public Sub New()
Me.New(100)
items.Add("default")
End Sub
Public Sub New(n As Integer)
MyBase.New(n - 1)
max = n
End Sub
End Class
Contoh sesuai dengan kode yang ditunjukkan di bawah ini, di mana setiap komentar menunjukkan pernyataan yang disisipkan secara otomatis.
Class A
Private x, y, count As Integer
Public Sub New()
MyBase.New ' Invoke object() constructor.
x = 1 ' This is a variable initializer.
y = -1 ' This is a variable initializer.
count = 0
End Sub
Public Sub New(n As Integer)
MyBase.New ' Invoke object() constructor.
x = 1 ' This is a variable initializer.
y = - 1 ' This is a variable initializer.
count = n
End Sub
End Class
Class B
Inherits A
Private sqrt2 As Double
Private items As ArrayList
Private max As Integer
Public Sub New()
Me.New(100)
items.Add("default")
End Sub
Public Sub New(n As Integer)
MyBase.New(n - 1)
sqrt2 = Math.Sqrt(2.0) ' This is a variable initializer.
items = New ArrayList(100) ' This is a variable initializer.
max = n
End Sub
End Class
Semua variabel diinisialisasi ke nilai default dari jenisnya sebelum penginisialisasi variabel dijalankan. Contohnya:
Class Test
Public Shared b As Boolean
Public i As Integer
End Class
Module TestModule
Sub Main()
Dim t As New Test()
Console.WriteLine("b = " & Test.b & ", i = " & t.i)
End Sub
End Module
Karena b secara otomatis diinisialisasi ke nilai defaultnya ketika kelas dimuat dan i secara otomatis diinisialisasi ke nilai defaultnya ketika instans kelas dibuat, kode sebelumnya menghasilkan output berikut:
b = False, i = 0
Setiap penginisialisasi variabel harus menghasilkan nilai dari jenis variabel atau jenis yang secara implisit dapat dikonversi ke jenis variabel. Penginisialisasi variabel mungkin melingkar atau merujuk ke variabel yang akan diinisialisasi setelahnya, dalam hal ini nilai variabel yang dirujuk adalah nilai defaultnya untuk tujuan penginisialisasi. Inisialisasi seperti itu adalah nilai yang meragukan.
Ada tiga bentuk penginisialisasi variabel: inisialisasi reguler, penginisialisasi ukuran array, dan penginisialisasi objek. Dua formulir pertama muncul setelah tanda sama dengan yang mengikuti nama jenis, dua yang terakhir adalah bagian dari deklarasi itu sendiri. Hanya satu bentuk penginisialisasi yang dapat digunakan pada deklarasi tertentu.
Penginisialisasi Reguler
Penginisialisasi reguler adalah ekspresi yang secara implisit dapat dikonversi ke jenis variabel. Muncul setelah tanda sama dengan yang mengikuti nama jenis dan harus diklasifikasikan sebagai nilai. Contohnya:
Module Test
Dim x As Integer = 10
Dim y As Integer = 20
Sub Main()
Console.WriteLine("x = " & x & ", y = " & y)
End Sub
End Module
Program ini menghasilkan output:
x = 10, y = 20
Jika deklarasi variabel memiliki penginisialisasi reguler, maka hanya satu variabel yang dapat dideklarasikan pada satu waktu. Contohnya:
Module Test
Sub Main()
' OK, only one variable declared at a time.
Dim x As Integer = 10, y As Integer = 20
' Error: Can't initialize multiple variables at once.
Dim a, b As Integer = 10
End Sub
End Module
Penginisialisasi Objek
Penginisialisasi objek ditentukan menggunakan ekspresi pembuatan objek di tempat nama jenis. Penginisialisasi objek setara dengan penginisialisasi reguler yang menetapkan hasil ekspresi pembuatan objek ke variabel. Jadi
Module TestModule
Sub Main()
Dim x As New Test(10)
End Sub
End Module
setara dengan:
Module TestModule
Sub Main()
Dim x As Test = New Test(10)
End Sub
End Module
Tanda kurung dalam penginisialisasi objek selalu ditafsirkan sebagai daftar argumen untuk konstruktor dan tidak pernah sebagai pengubah jenis array. Nama variabel dengan penginisialisasi objek tidak dapat memiliki pengubah tipe array atau pengubah tipe yang dapat diubah ke null.
Penginisialisasi Array-Size
Penginisialisasi ukuran array adalah pengubah pada nama variabel yang memberikan sekumpulan batas atas dimensi yang ditandai oleh ekspresi.
ArraySizeInitializationModifier
: OpenParenthesis BoundList CloseParenthesis ArrayTypeModifiers?
;
BoundList
: Bound ( Comma Bound )*
;
Bound
: Expression
| '0' 'To' Expression
;
Ekspresi terikat atas harus diklasifikasikan sebagai nilai dan harus secara implisit dapat dikonversi ke Integer. Kumpulan batas atas setara dengan penginisialisasi variabel ekspresi pembuatan array dengan batas atas yang diberikan. Jumlah dimensi jenis array disimpulkan dari penginisialisasi ukuran array. Jadi
Module Test
Sub Main()
Dim x(5, 10) As Integer
End Sub
End Module
setara dengan:
Module Test
Sub Main()
Dim x As Integer(,) = New Integer(5, 10) {}
End Sub
End Module
Semua batas atas harus sama dengan atau lebih besar dari -1, dan semua dimensi harus memiliki batas atas yang ditentukan. Jika jenis elemen array yang diinisialisasi adalah jenis array itu sendiri, pengubah jenis array masuk ke sebelah kanan penginisialisasi ukuran array. Misalnya
Module Test
Sub Main()
Dim x(5,10)(,,) As Integer
End Sub
End Module
mendeklarasikan variabel x lokal yang jenisnya adalah array dua dimensi dari array Integertiga dimensi , diinisialisasi ke array dengan batas 0..5 dalam dimensi pertama dan 0..10 di dimensi kedua. Tidak dimungkinkan untuk menggunakan penginisialisasi ukuran array untuk menginisialisasi elemen variabel yang jenisnya adalah array.
Deklarasi variabel dengan penginisialisasi ukuran array tidak dapat memiliki pengubah jenis array pada jenisnya atau penginisialisasi reguler.
Kelas System.MarshalByRefObject
Kelas yang berasal dari kelas System.MarshalByRefObject dinaungi di seluruh batas konteks menggunakan proksi (yaitu, berdasarkan referensi) daripada melalui penyalinan (yaitu, berdasarkan nilai). Ini berarti bahwa instans kelas seperti itu mungkin bukan instans yang benar tetapi mungkin hanya pangkal yang dapat diakses variabel marshal dan panggilan metode di seluruh batas konteks.
Akibatnya, tidak mungkin untuk membuat referensi ke lokasi penyimpanan variabel yang ditentukan pada kelas tersebut. Ini berarti bahwa variabel yang di ketik sebagai kelas yang berasal dari System.MarshalByRefObject tidak dapat diteruskan ke parameter referensi, dan metode dan variabel variabel yang di ketik sebagai jenis nilai mungkin tidak diakses. Sebaliknya, Visual Basic memperlakukan variabel yang ditentukan pada kelas tersebut seolah-olah itu adalah properti (karena pembatasannya sama pada properti).
Ada satu pengecualian untuk aturan ini: anggota yang memenuhi syarat secara implisit atau eksplisit dikecualikan dari batasan di atas, karena Me selalu dijamin sebagai objek aktualMe, bukan proksi.
Karakteristik
Properti adalah ekstensi alami variabel; keduanya diberi nama anggota dengan jenis terkait, dan sintaks untuk mengakses variabel dan properti sama. Namun, tidak seperti variabel, properti tidak menunjukkan lokasi penyimpanan. Sebagai gantinya, properti memiliki aksesor, yang menentukan pernyataan yang akan dijalankan untuk membaca atau menulis nilainya.
Properti didefinisikan dengan deklarasi properti. Bagian pertama dari deklarasi properti menyerupan deklarasi bidang. Bagian kedua mencakup Get aksesor dan/atau Set aksesor.
PropertyMemberDeclaration
: RegularPropertyMemberDeclaration
| MustOverridePropertyMemberDeclaration
| AutoPropertyMemberDeclaration
;
PropertySignature
: 'Property'
Identifier ( OpenParenthesis ParameterList? CloseParenthesis )?
( 'As' Attributes? TypeName )?
;
RegularPropertyMemberDeclaration
: Attributes? PropertyModifier* PropertySignature
ImplementsClause? LineTerminator
PropertyAccessorDeclaration+
'End' 'Property' StatementTerminator
;
MustOverridePropertyMemberDeclaration
: Attributes? MustOverridePropertyModifier+ PropertySignature
ImplementsClause? StatementTerminator
;
AutoPropertyMemberDeclaration
: Attributes? AutoPropertyModifier* 'Property' Identifier
( OpenParenthesis ParameterList? CloseParenthesis )?
( 'As' Attributes? TypeName )? ( Equals Expression )?
ImplementsClause? LineTerminator
| Attributes? AutoPropertyModifier* 'Property' Identifier
( OpenParenthesis ParameterList? CloseParenthesis )?
'As' Attributes? 'New'
( NonArrayTypeName ( OpenParenthesis ArgumentList? CloseParenthesis )? )?
ObjectCreationExpressionInitializer?
ImplementsClause? LineTerminator
;
InterfacePropertyMemberDeclaration
: Attributes? InterfacePropertyModifier* PropertySignature StatementTerminator
;
AutoPropertyModifier
: AccessModifier
| 'Shadows'
| 'Shared'
| 'Overridable'
| 'NotOverridable'
| 'Overrides'
| 'Overloads'
;
PropertyModifier
: AutoPropertyModifier
| 'Default'
| 'ReadOnly'
| 'WriteOnly'
| 'Iterator'
;
MustOverridePropertyModifier
: PropertyModifier
| 'MustOverride'
;
InterfacePropertyModifier
: 'Shadows'
| 'Overloads'
| 'Default'
| 'ReadOnly'
| 'WriteOnly'
;
PropertyAccessorDeclaration
: PropertyGetDeclaration
| PropertySetDeclaration
;
Dalam contoh di bawah ini, Button kelas menentukan Caption properti.
Public Class Button
Private captionValue As String
Public Property Caption() As String
Get
Return captionValue
End Get
Set (Value As String)
captionValue = value
Repaint()
End Set
End Property
...
End Class
Berdasarkan kelas di Button atas, berikut ini adalah contoh penggunaan Caption properti:
Dim okButton As Button = New Button()
okButton.Caption = "OK" ' Invokes Set accessor.
Dim s As String = okButton.Caption ' Invokes Get accessor.
Di sini, Set aksesor dipanggil dengan menetapkan nilai ke properti , dan Get aksesor dipanggil dengan mereferensikan properti dalam ekspresi.
Jika tidak ada jenis yang ditentukan untuk properti dan semantik ketat yang digunakan, kesalahan waktu kompilasi terjadi; jika tidak, jenis properti secara Object implisit atau jenis karakter jenis properti. Deklarasi properti mungkin berisi Get aksesor, yang mengambil nilai properti, Set aksesor, yang menyimpan nilai properti, atau keduanya. Karena properti secara implisit menyatakan metode, properti dapat dinyatakan dengan pengubah yang sama sebagai metode. Jika properti didefinisikan dalam antarmuka atau didefinisikan dengan MustOverride pengubah, isi properti dan End konstruksi harus dihilangkan; jika tidak, kesalahan waktu kompilasi terjadi.
Daftar parameter indeks membentuk tanda tangan properti, sehingga properti mungkin kelebihan beban pada parameter indeks tetapi tidak pada jenis properti. Daftar parameter indeks sama dengan untuk metode reguler. Namun, tidak ada parameter yang dapat dimodifikasi dengan ByRef pengubah dan tidak ada yang dapat dinamai Value (yang dicadangkan untuk parameter nilai implisit di Set aksesor).
Properti dapat dinyatakan sebagai berikut:
Jika properti tidak menentukan pengubah jenis properti, properti harus memiliki
Getaksesor danSetaksesor. Properti ini dikatakan sebagai properti baca-tulis.Jika properti menentukan pengubah
ReadOnly, properti harus memilikiGetaksesor dan mungkin tidak memilikiSetaksesor. Properti ini dikatakan sebagai properti baca-saja. Ini adalah kesalahan waktu kompilasi jika properti baca-saja menjadi target penugasan.Jika properti menentukan pengubah
WriteOnly, properti harus memilikiSetaksesor dan mungkin tidak memilikiGetaksesor. Properti ini dikatakan sebagai properti tulis-saja. Ini adalah kesalahan waktu kompilasi untuk mereferensikan properti tulis-saja dalam ekspresi kecuali sebagai target penugasan atau sebagai argumen ke metode.
Aksesor Get dan Set properti bukan anggota yang berbeda, dan tidak dimungkinkan untuk mendeklarasikan aksesor properti secara terpisah. Contoh berikut tidak mendeklarasikan satu properti baca-tulis. Sebaliknya, ia mendeklarasikan dua properti dengan nama yang sama, satu baca-saja dan satu tulis-saja:
Class A
Private nameValue As String
' Error, contains a duplicate member name.
Public ReadOnly Property Name() As String
Get
Return nameValue
End Get
End Property
' Error, contains a duplicate member name.
Public WriteOnly Property Name() As String
Set (Value As String)
nameValue = value
End Set
End Property
End Class
Karena dua anggota yang dinyatakan dalam kelas yang sama tidak dapat memiliki nama yang sama, contoh tersebut menyebabkan kesalahan waktu kompilasi.
Secara default, aksesibilitas properti Get dan Set aksesor sama dengan aksesibilitas properti itu sendiri. Namun, aksesor Get dan Set juga dapat menentukan aksesibilitas secara terpisah dari properti. Dalam hal ini, aksesibilitas aksesor harus lebih ketat daripada aksesibilitas properti dan hanya satu aksesor yang dapat memiliki tingkat aksesibilitas yang berbeda dari properti. Jenis akses dianggap kurang lebih ketat sebagai berikut:
Privatelebih ketat daripadaPublic, ,Protected FriendProtected, atauFriend.Friendlebih ketat daripadaProtected FriendatauPublic.Protectedlebih ketat daripadaProtected FriendatauPublic.Protected Friendlebih ketat daripadaPublic.
Ketika salah satu aksesor properti dapat diakses tetapi yang lain tidak, properti diperlakukan seolah-olah itu baca-saja atau tulis-saja. Contohnya:
Class A
Public Property P() As Integer
Get
...
End Get
Private Set (Value As Integer)
...
End Set
End Property
End Class
Module Test
Sub Main()
Dim a As A = New A()
' Error: A.P is read-only in this context.
a.P = 10
End Sub
End Module
Ketika jenis turunan membayangi properti, properti turunan menyembunyikan properti berbayang sehubungan dengan pembacaan dan penulisan. Dalam contoh berikut, P properti di B menyembunyikan P properti A sehubungan dengan pembacaan dan penulisan:
Class A
Public WriteOnly Property P() As Integer
Set (Value As Integer)
End Set
End Property
End Class
Class B
Inherits A
Public Shadows ReadOnly Property P() As Integer
Get
End Get
End Property
End Class
Module Test
Sub Main()
Dim x As B = New B
B.P = 10 ' Error, B.P is read-only.
End Sub
End Module
Domain aksesibilitas jenis pengembalian atau jenis parameter harus sama dengan atau superset domain aksesibilitas properti itu sendiri. Properti mungkin hanya memiliki satu Set aksesor dan satu Get aksesor.
Kecuali untuk perbedaan dalam sintaks deklarasi dan pemanggilan, Overridable, , NotOverridable, MustOverrideOverrides, , dan MustInherit berulah persis seperti Overridablemetode , , NotOverridableOverrides, MustOverride, dan MustInherit . Ketika properti ditimpa, properti penggantian harus dengan jenis yang sama (baca-tulis, baca-saja, tulis-saja). Properti Overridable tidak boleh berisi Private pengaktor.
Dalam contoh X berikut adalah Overridable properti baca-saja, Y adalah Overridable properti baca-tulis, dan Z merupakan MustOverride properti baca-tulis.
MustInherit Class A
Private _y As Integer
Public Overridable ReadOnly Property X() As Integer
Get
Return 0
End Get
End Property
Public Overridable Property Y() As Integer
Get
Return _y
End Get
Set (Value As Integer)
_y = value
End Set
End Property
Public MustOverride Property Z() As Integer
End Class
Karena Z adalah MustOverride, kelas A yang berisi harus dinyatakan MustInherit.
Sebaliknya, kelas yang berasal dari kelas A ditunjukkan di bawah ini:
Class B
Inherits A
Private _z As Integer
Public Overrides ReadOnly Property X() As Integer
Get
Return MyBase.X + 1
End Get
End Property
Public Overrides Property Y() As Integer
Get
Return MyBase.Y
End Get
Set (Value As Integer)
If value < 0 Then
MyBase.Y = 0
Else
MyBase.Y = Value
End If
End Set
End Property
Public Overrides Property Z() As Integer
Get
Return _z
End Get
Set (Value As Integer)
_z = Value
End Set
End Property
End Class
Di sini, deklarasi properti X,Y , dan Z mengambil alih properti dasar. Setiap deklarasi properti sama persis dengan pengubah aksesibilitas, jenis, dan nama properti yang diwariskan yang sesuai. Aksesor Get properti X dan Set aksesor properti Y menggunakan MyBase kata kunci untuk mengakses properti yang diwariskan. Deklarasi properti Z mengambil alih MustOverride properti -- dengan demikian, tidak ada anggota terutang MustOverride di kelas B, dan B diizinkan untuk menjadi kelas reguler.
Properti dapat digunakan untuk menunda inisialisasi sumber daya sampai saat pertama kali direferensikan. Contohnya:
Imports System.IO
Public Class ConsoleStreams
Private Shared reader As TextReader
Private Shared writer As TextWriter
Private Shared errors As TextWriter
Public Shared ReadOnly Property [In]() As TextReader
Get
If reader Is Nothing Then
reader = Console.In
End If
Return reader
End Get
End Property
Public Shared ReadOnly Property Out() As TextWriter
Get
If writer Is Nothing Then
writer = Console.Out
End If
Return writer
End Get
End Property
Public Shared ReadOnly Property [Error]() As TextWriter
Get
If errors Is Nothing Then
errors = Console.Error
End If
Return errors
End Get
End Property
End Class
Kelas ConsoleStreams berisi tiga properti, In, Out, dan Error, yang mewakili perangkat input, output, dan perangkat kesalahan standar. Dengan mengekspos anggota ini sebagai properti, ConsoleStreams kelas dapat menunda inisialisasi mereka sampai mereka benar-benar digunakan. Misalnya, setelah pertama kali merujuk properti Out , seperti dalam ConsoleStreams.Out.WriteLine("hello, world"), yang mendasari TextWriter untuk perangkat output diinisialisasi. Tetapi jika aplikasi tidak membuat referensi ke In properti dan Error , maka tidak ada objek yang dibuat untuk perangkat tersebut.
Dapatkan Deklarasi Aksesor
Aksesor Get (getter) dinyatakan dengan menggunakan deklarasi properti Get . Deklarasi properti Get terdiri dari kata kunci Get diikuti oleh blok pernyataan. Mengingat properti bernama P, Get deklarasi pengakses secara implisit mendeklarasikan metode dengan nama get_P dengan pengubah, jenis, dan daftar parameter yang sama dengan properti . Jika jenis berisi deklarasi dengan nama tersebut, kesalahan waktu kompilasi menghasilkan, tetapi deklarasi implisit diabaikan untuk tujuan pengikatan nama.
Variabel lokal khusus, yang secara implisit dideklarasikan dalam Get ruang deklarasi isi aksesor dengan nama yang sama dengan properti , mewakili nilai pengembalian properti. 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:
ReadOnly Property F(i As Integer) As Integer
Get
If i = 0 Then
F = 1 ' Sets the return value.
Else
F = F(i - 1) ' Recursive call.
End If
End Get
End Property
Penggunaan tanda kurung dapat menyebabkan situasi ambigu (seperti F(1) di mana F adalah properti yang jenisnya adalah array satu dimensi). Dalam semua situasi ambigu, nama diselesaikan ke properti daripada variabel lokal. Contohnya:
ReadOnly Property F(i As Integer) As Integer()
Get
If i = 0 Then
F = new Integer(2) { 1, 2, 3 }
Else
F = F(i - 1) ' Recursive call, not index.
End If
End Get
End Property
Ketika alur kontrol meninggalkan Get isi aksesor, nilai variabel lokal diteruskan kembali ke ekspresi pemanggilan. Karena memanggil Get aksesor secara konseptual setara dengan membaca nilai variabel, itu dianggap gaya pemrograman yang buruk bagi Get aksesor untuk memiliki efek samping yang dapat diamati, seperti yang diilustrasikan dalam contoh berikut:
Class Counter
Private Value As Integer
Public ReadOnly Property NextValue() As Integer
Get
Value += 1
Return Value
End Get
End Property
End Class
Nilai NextValue properti tergantung pada berapa kali properti sebelumnya diakses. Dengan demikian, mengakses properti menghasilkan efek samping yang dapat diamati, dan properti harus diimplementasikan sebagai metode.
Konvensi "tidak ada efek samping" untuk Get pengakses tidak berarti bahwa Get pengakses harus selalu ditulis untuk hanya mengembalikan nilai yang disimpan dalam variabel. Memang, Get aksesor sering menghitung nilai properti dengan mengakses beberapa variabel atau memanggil metode. Namun, aksesor yang dirancang Get dengan benar tidak melakukan tindakan yang menyebabkan perubahan yang dapat diamati dalam status objek.
Nota.
Get aksesor memiliki batasan yang sama pada penempatan baris yang dimiliki sub-rutin. Pernyataan awal, pernyataan akhir, dan blok semuanya harus muncul di awal baris logis.
PropertyGetDeclaration
: Attributes? AccessModifier? 'Get' LineTerminator
Block?
'End' 'Get' StatementTerminator
;
Mengatur Deklarasi Aksesor
Aksesor Set (setter) dideklarasikan dengan menggunakan deklarasi set properti. Deklarasi kumpulan properti terdiri dari kata kunci Set, daftar parameter opsional, dan blok pernyataan. Mengingat properti bernama P, deklarasi setter secara implisit mendeklarasikan metode dengan nama set_P dengan pengubah dan daftar parameter yang sama dengan properti . Jika jenis berisi deklarasi dengan nama tersebut, kesalahan waktu kompilasi menghasilkan, tetapi deklarasi implisit diabaikan untuk tujuan pengikatan nama.
Jika daftar parameter ditentukan, daftar harus memiliki satu anggota, anggota tersebut tidak boleh memiliki pengubah kecuali ByVal, dan jenisnya harus sama dengan jenis properti. Parameter mewakili nilai properti yang ditetapkan. Jika parameter dihilangkan, parameter bernama Value dideklarasikan secara implisit.
Nota.
Set aksesor memiliki batasan yang sama pada penempatan baris yang dimiliki sub-rutin. Pernyataan awal, pernyataan akhir, dan blok semuanya harus muncul di awal baris logis.
PropertySetDeclaration
: Attributes? AccessModifier? 'Set'
( OpenParenthesis ParameterList? CloseParenthesis )? LineTerminator
Block?
'End' 'Set' StatementTerminator
;
Properti Default
Properti yang menentukan pengubah Default disebut properti default. Jenis apa pun yang memungkinkan properti mungkin memiliki properti default, termasuk antarmuka. Properti default dapat dirujuk tanpa harus memenuhi syarat instans dengan nama properti . Dengan demikian, diberi kelas
Class Test
Public Default ReadOnly Property Item(i As Integer) As Integer
Get
Return i
End Get
End Property
End Class
kode
Module TestModule
Sub Main()
Dim x As Test = New Test()
Dim y As Integer
y = x(10)
End Sub
End Module
setara dengan:
Module TestModule
Sub Main()
Dim x As Test = New Test()
Dim y As Integer
y = x.Item(10)
End Sub
End Module
Setelah properti dinyatakan Default, semua properti yang kelebihan beban pada nama tersebut dalam hierarki warisan menjadi properti default, apakah properti tersebut telah dideklarasikan Default atau tidak. Mendeklarasikan properti Default di kelas turunan ketika kelas dasar mendeklarasikan properti default dengan nama lain tidak memerlukan pengubah lain seperti Shadows atau Overrides. Ini karena properti default tidak memiliki identitas atau tanda tangan sehingga tidak dapat dibayangi atau kelebihan beban. Contohnya:
Class Base
Public ReadOnly Default Property Item(i As Integer) As Integer
Get
Console.WriteLine("Base = " & i)
End Get
End Property
End Class
Class Derived
Inherits Base
' This hides Item, but does not change the default property.
Public Shadows ReadOnly Property Item(i As Integer) As Integer
Get
Console.WriteLine("Derived = " & i)
End Get
End Property
End Class
Class MoreDerived
Inherits Derived
' This declares a new default property, but not Item.
' This does not need to be declared Shadows
Public ReadOnly Default Property Value(i As Integer) As Integer
Get
Console.WriteLine("MoreDerived = " & i)
End Get
End Property
End Class
Module Test
Sub Main()
Dim x As MoreDerived = New MoreDerived()
Dim y As Integer
Dim z As Derived = x
y = x(10) ' Calls MoreDerived.Value.
y = x.Item(10) ' Calls Derived.Item
y = z(10) ' Calls Base.Item
End Sub
End Module
Program ini akan menghasilkan output:
MoreDerived = 10
Derived = 10
Base = 10
Semua properti default yang dideklarasikan dalam jenis harus memiliki nama yang sama dan, untuk kejelasan, harus menentukan pengubah Default . Karena properti default tanpa parameter indeks akan menyebabkan situasi ambigu saat menetapkan instans kelas yang berisi, properti default harus memiliki parameter indeks. Selain itu, jika satu properti kelebihan beban pada nama tertentu menyertakan Default pengubah, semua properti yang kelebihan beban pada nama tersebut harus menentukannya. Properti default mungkin Sharedbukan , dan setidaknya satu aksesor properti tidak boleh Private.
Properti yang Diimplementasikan Secara Otomatis
Jika properti menghilangkan deklarasi aksesor apa pun, implementasi properti akan secara otomatis disediakan kecuali properti dideklarasikan dalam antarmuka atau dinyatakan MustOverride. Hanya properti baca/tulis tanpa argumen yang dapat diimplementasikan secara otomatis; jika tidak, terjadi kesalahan waktu kompilasi.
Properti xyang diimplementasikan secara otomatis , bahkan satu menimpa properti lain, memperkenalkan variabel _x lokal privat dengan jenis yang sama dengan properti . Jika ada tabrakan antara nama variabel lokal dan deklarasi lain, kesalahan waktu kompilasi akan dilaporkan. Aksesor properti Get yang diimplementasikan secara otomatis mengembalikan nilai lokal dan aksesor properti Set yang menetapkan nilai lokal. Misalnya, deklarasi:
Public Property x() As Integer
kira-kira setara dengan:
Private _x As Integer
Public Property x() As Integer
Get
Return _x
End Get
Set (value As Integer)
_x = value
End Set
End Property
Seperti halnya deklarasi variabel, properti yang diimplementasikan secara otomatis dapat menyertakan penginisialisasi. Contohnya:
Public Property x() As Integer = 10
Public Shared Property y() As New Customer() With { .Name = "Bob" }
Nota. Ketika properti yang diimplementasikan secara otomatis diinisialisasi, properti diinisialisasi melalui properti , bukan bidang yang mendasar. Ini sangat mengesampingkan properti dapat mencegat inisialisasi jika perlu.
Penginisialisasi array diizinkan pada properti yang diimplementasikan secara otomatis, kecuali bahwa tidak ada cara untuk menentukan batas array secara eksplisit. Contohnya:
' Valid
Property x As Integer() = {1, 2, 3}
Property y As Integer(,) = {{1, 2, 3}, {12, 13, 14}, {11, 10, 9}}
' Invalid
Property x4(5) As Short
Properti Iterator
Properti iterator adalah properti dengan pengubahIterator. Ini digunakan untuk alasan yang sama metode iterator ( Bagian Metode Iterator) digunakan -- sebagai cara yang nyaman untuk menghasilkan urutan, yang dapat dikonsumsi oleh For Each pernyataan. Aksesor Get properti iterator ditafsirkan dengan cara yang sama seperti metode iterator.
Properti iterator harus memiliki aksesor eksplisit Get , dan jenisnya harus IEnumerator, atau IEnumerable, atau atau IEnumerator(Of T)IEnumerable(Of T) untuk beberapa T.
Berikut adalah contoh properti iterator:
Class Family
Property Daughters As New List(Of String) From {"Beth", "Diane"}
Property Sons As New List(Of String) From {"Abe", "Carl"}
ReadOnly Iterator Property Children As IEnumerable(Of String)
Get
For Each name In Daughters : Yield name : Next
For Each name In Sons : Yield name : Next
End Get
End Property
End Class
Module Module1
Sub Main()
Dim x As New Family
For Each c In x.Children
Console.WriteLine(c) ' prints Beth, Diane, Abe, Carl
Next
End Sub
End Module
Para Operator
Operator adalah metode yang menentukan arti operator Visual Basic yang ada untuk kelas yang berisi. Saat operator diterapkan ke kelas dalam ekspresi, operator dikompilasi ke dalam panggilan ke metode operator yang ditentukan di kelas . Menentukan operator untuk kelas juga dikenal sebagai kelebihan beban operator.
OperatorDeclaration
: Attributes? OperatorModifier* 'Operator' OverloadableOperator
OpenParenthesis ParameterList CloseParenthesis
( 'As' Attributes? TypeName )? LineTerminator
Block?
'End' 'Operator' StatementTerminator
;
OperatorModifier
: 'Public' | 'Shared' | 'Overloads' | 'Shadows' | 'Widening' | 'Narrowing'
;
OverloadableOperator
: '+' | '-' | '*' | '/' | '\\' | '&' | 'Like' | 'Mod' | 'And' | 'Or' | 'Xor'
| '^' | '<' '<' | '>' '>' | '=' | '<' '>' | '>' | '<' | '>' '=' | '<' '='
| 'Not' | 'IsTrue' | 'IsFalse' | 'CType'
;
Tidak dimungkinkan untuk membebani operator yang sudah ada; dalam praktiknya, ini terutama berlaku untuk operator konversi. Misalnya, tidak dimungkinkan untuk membebani konversi dari kelas turunan ke kelas dasar:
Class Base
End Class
Class Derived
' Cannot redefine conversion from Derived to Base,
' conversion will be ignored.
Public Shared Widening Operator CType(s As Derived) As Base
...
End Operator
End Class
Operator juga dapat kelebihan beban dalam arti umum kata:
Class Base
Public Shared Widening Operator CType(b As Base) As Integer
...
End Operator
Public Shared Narrowing Operator CType(i As Integer) As Base
...
End Operator
End Class
Deklarasi operator tidak secara eksplisit menambahkan nama ke ruang deklarasi jenis yang berisi; namun mereka secara implisit menyatakan metode yang sesuai dimulai dengan karakter "op_". Bagian berikut mencantumkan nama metode yang sesuai dengan setiap operator.
Ada tiga kelas operator yang dapat ditentukan: operator unary, operator biner, dan operator konversi. Semua deklarasi operator berbagi batasan tertentu:
Deklarasi operator harus
Publicselalu danShared. PengubahPublicdapat dihilangkan dalam konteks di mana pengubah akan diasumsikan.Parameter operator tidak dapat dideklarasikan
ByRef,OptionalatauParamArray.Jenis setidaknya salah satu operand atau nilai yang dikembalikan harus berupa jenis yang berisi operator.
Tidak ada variabel pengembalian fungsi yang ditentukan untuk operator. Oleh karena itu,
Returnpernyataan harus digunakan untuk mengembalikan nilai dari isi operator.
Satu-satunya pengecualian untuk pembatasan ini berlaku untuk jenis nilai nullable. Karena jenis nilai nullable tidak memiliki definisi jenis aktual, jenis nilai dapat mendeklarasikan operator yang ditentukan pengguna untuk versi tipe yang dapat diubah ke null. Saat menentukan apakah jenis dapat mendeklarasikan operator tertentu yang ditentukan pengguna, ? pengubah pertama kali diturunkan dari semua jenis yang terlibat dalam deklarasi untuk tujuan pemeriksaan validitas. Relaksasi ini tidak berlaku untuk jenis IsTrue pengembalian operator dan IsFalse ; mereka masih harus mengembalikan Boolean, bukan Boolean?.
Prioritas dan asokiativitas operator tidak dapat dimodifikasi oleh deklarasi operator.
Nota. Operator memiliki batasan yang sama pada penempatan baris yang dimiliki subroutine. Pernyataan awal, pernyataan akhir, dan blok semuanya harus muncul di awal baris logis.
Operator Unary
Operator unary berikut dapat kelebihan beban:
Operator
+unary plus (metode yang sesuai:op_UnaryPlus)Operator
-minus unary (metode yang sesuai:op_UnaryNegation)Operator logis
Not(metode yang sesuai:op_OnesComplement)Operator
IsTruedanIsFalse(metode yang sesuai:op_True,op_False)
Semua operator unary yang kelebihan beban harus mengambil satu parameter dari jenis yang berisi dan dapat mengembalikan jenis apa pun, kecuali untuk IsTrue dan IsFalse, yang harus mengembalikan Boolean. Jika jenis yang berisi adalah jenis generik, parameter jenis harus cocok dengan parameter jenis yang berisi. Contohnya,
Structure Complex
...
Public Shared Operator +(v As Complex) As Complex
Return v
End Operator
End Structure
Jika jenis kelebihan beban salah IsTrue satu dari atau IsFalse, maka harus kelebihan beban yang lain juga. Jika hanya satu yang kelebihan beban, kesalahan waktu kompilasi akan menghasilkan.
Nota.
IsTrue dan IsFalse bukan kata-kata yang dicadangkan.
Operator Biner
Operator biner berikut dapat kelebihan beban:
Penambahan
+, pengurangan-, perkalian*, divisi/, divisi\integral , operator moduloModdan eksponensiasi^(metode yang sesuai:op_Addition, ,op_Subtractionop_Multiply,op_Division,op_IntegerDivision,op_Modulusop_Exponent)Operator
=relasional , ,<>,><,<=,>=(metode yang sesuai:op_Equality, ,op_Inequality,op_LessThanop_GreaterThan,op_LessThanOrEqual,op_GreaterThanOrEqual). Nota. Meskipun operator kesetaraan dapat kelebihan beban, operator penugasan (hanya digunakan dalam pernyataan penugasan) tidak dapat kelebihan beban.Operator
Like(metode yang sesuai:op_Like)Operator
&perangkaian (metode yang sesuai:op_Concatenate)Operator logis
And,OrdanXor(metode yang sesuai:op_BitwiseAnd, ,op_BitwiseOrop_ExclusiveOr)Operator
<<shift dan>>(metode yang sesuai:op_LeftShift,op_RightShift)
Semua operator biner yang kelebihan beban harus mengambil jenis yang berisi sebagai salah satu parameter. Jika jenis yang berisi adalah jenis generik, parameter jenis harus cocok dengan parameter jenis yang berisi. Operator shift selanjutnya membatasi aturan ini untuk mengharuskan parameter pertama dari jenis yang berisi; parameter kedua harus selalu berjenis Integer.
Operator biner berikut harus dideklarasikan berpasangan:
Operator
=dan operator<>Operator
>dan operator<Operator
>=dan operator<=
Jika salah satu pasangan dideklarasikan, maka pasangan lainnya juga harus dideklarasikan dengan parameter yang cocok dan jenis pengembalian, atau kesalahan waktu kompilasi akan dihasilkan. (Catatan. Tujuan mengharuskan deklarasi berpasangan operator relasional adalah untuk mencoba dan memastikan setidaknya tingkat minimum konsistensi logis pada operator yang kelebihan beban.)
Berbeda dengan operator relasional, kelebihan beban operator divisi dan divisi integral sangat tidak dianjurkan, meskipun bukan kesalahan. (Catatan. Secara umum, dua jenis pembagian harus sepenuhnya berbeda: jenis yang mendukung pembagian adalah integral (dalam hal ini harus mendukung \) atau tidak (dalam hal ini harus mendukung /). Kami mempertimbangkan untuk menjadikannya kesalahan untuk menentukan kedua operator, tetapi karena bahasa mereka umumnya tidak membedakan antara dua jenis pembagian seperti yang dilakukan Visual Basic, kami merasa paling aman untuk memungkinkan praktik tetapi sangat mencegahnya.)
Operator penetapan gabungan tidak dapat kelebihan beban secara langsung. Sebagai gantinya, ketika operator biner yang sesuai kelebihan beban, operator penetapan majemuk akan menggunakan operator yang kelebihan beban. Contohnya:
Structure Complex
...
Public Shared Operator +(x As Complex, y As Complex) _
As Complex
...
End Operator
End Structure
Module Test
Sub Main()
Dim c1, c2 As Complex
' Calls the overloaded + operator
c1 += c2
End Sub
End Module
Operator Konversi
Operator konversi menentukan konversi baru di antara jenis. Konversi baru ini disebut konversi yang ditentukan pengguna. Operator konversi dikonversi dari jenis sumber, yang ditunjukkan oleh jenis parameter operator konversi, ke jenis target, yang ditunjukkan oleh jenis pengembalian operator konversi. Konversi harus diklasifikasikan sebagai pelesiran atau penyempitan. Deklarasi operator konversi yang menyertakan Widening kata kunci memperkenalkan konversi pelesiran yang ditentukan pengguna (metode yang sesuai: op_Implicit). Deklarasi operator konversi yang menyertakan Narrowing kata kunci memperkenalkan konversi penyempitan yang ditentukan pengguna (metode yang sesuai: op_Explicit).
Secara umum, konversi pelesiran yang ditentukan pengguna harus dirancang untuk tidak pernah melemparkan pengecualian dan tidak pernah kehilangan informasi. Jika konversi yang ditentukan pengguna dapat menyebabkan pengecualian (misalnya, karena argumen sumber berada di luar rentang) atau hilangnya informasi (seperti membuang bit berurutan tinggi), konversi tersebut harus didefinisikan sebagai konversi yang mempersempit. Dalam contoh:
Structure Digit
Dim value As Byte
Public Sub New(value As Byte)
if value < 0 OrElse value > 9 Then Throw New ArgumentException()
Me.value = value
End Sub
Public Shared Widening Operator CType(d As Digit) As Byte
Return d.value
End Operator
Public Shared Narrowing Operator CType(b As Byte) As Digit
Return New Digit(b)
End Operator
End Structure
konversi dari Digit ke Byte adalah konversi yang melebar karena tidak pernah melemparkan pengecualian atau kehilangan informasi, tetapi konversi dari Byte ke Digit adalah konversi yang menyempit karena Digit hanya dapat mewakili subset dari nilai yang Bytemungkin dari .
Tidak seperti semua anggota jenis lain yang dapat kelebihan beban, tanda tangan operator konversi mencakup jenis target konversi. Ini adalah satu-satunya anggota jenis yang jenis pengembaliannya berpartisipasi dalam tanda tangan. Klasifikasi operator konversi yang melebar atau dipersempit, namun, bukan bagian dari tanda tangan operator. Dengan demikian, kelas atau struktur tidak dapat mendeklarasikan operator konversi yang melebar dan operator konversi yang mempersempit dengan jenis sumber dan target yang sama.
Operator konversi yang ditentukan pengguna harus mengonversi ke atau dari jenis yang berisi -- misalnya, dimungkinkan bagi kelas C untuk menentukan konversi dari C ke Integer dan dari Integer ke C, tetapi tidak dari Integer ke Boolean. Jika jenis yang berisi adalah jenis generik, parameter jenis harus cocok dengan parameter jenis yang berisi. Selain itu, tidak mungkin untuk mendefinisikan ulang konversi intrinsik (yaitu tidak ditentukan pengguna). Akibatnya, jenis tidak dapat mendeklarasikan konversi di mana:
Jenis sumber dan jenis tujuannya sama.
Jenis sumber dan jenis tujuan bukan jenis yang menentukan operator konversi.
Jenis sumber atau jenis tujuan adalah jenis antarmuka.
Jenis sumber dan jenis tujuan terkait dengan pewarisan (termasuk
Object).
Satu-satunya pengecualian untuk aturan ini berlaku untuk jenis nilai nullable. Karena jenis nilai nullable tidak memiliki definisi jenis aktual, jenis nilai dapat mendeklarasikan konversi yang ditentukan pengguna untuk versi tipe yang dapat diubah ke null. Saat menentukan apakah jenis dapat mendeklarasikan konversi tertentu yang ditentukan pengguna, ? pengubah pertama kali diturunkan dari semua jenis yang terlibat dalam deklarasi untuk tujuan pemeriksaan validitas. Dengan demikian, deklarasi berikut valid karena S dapat menentukan konversi dari S ke T:
Structure T
...
End Structure
Structure S
Public Shared Widening Operator CType(ByVal v As S?) As T
...
End Operator
End Structure
Namun, deklarasi berikut tidak valid karena struktur S tidak dapat menentukan konversi dari S ke S:
Structure S
Public Shared Widening Operator CType(ByVal v As S) As S?
...
End Operator
End Structure
Pemetaan Operator
Karena sekumpulan operator yang didukung Visual Basic mungkin tidak sama persis dengan kumpulan operator yang digunakan bahasa lain pada .NET Framework, beberapa operator dipetakan khusus ke operator lain saat didefinisikan atau digunakan. Khususnya:
Menentukan operator divisi integral akan secara otomatis menentukan operator divisi reguler (hanya dapat digunakan dari bahasa lain) yang akan memanggil operator divisi integral.
Kelebihan beban
Notoperator ,And, danOrhanya akan membebani operator bitwise dari perspektif bahasa lain yang membedakan antara operator logis dan bitwise.Kelas yang hanya membebani operator logis dalam bahasa yang membedakan antara operator logis dan bitwise (yaitu bahasa yang menggunakan
op_LogicalNot, , danop_LogicalOruntukNot,op_LogicalAnd,AnddanOr, masing-masing) akan memiliki operator logis mereka yang dipetakan ke operator logis Visual Basic. Jika operator logis dan bitwise kelebihan beban, hanya operator bitwise yang akan digunakan.Kelebihan beban
<<operator dan>>hanya akan membebani operator yang ditandatangani dari perspektif bahasa lain yang membedakan antara operator shift yang ditandatangani dan tidak ditandatangani.Kelas yang hanya membebani operator shift yang tidak ditandatangani akan memiliki operator shift yang tidak ditandatangani yang dipetakan ke operator shift Visual Basic yang sesuai. Jika operator shift yang tidak ditandatangani dan ditandatangani kelebihan beban, hanya operator shift yang ditandatangani yang akan digunakan.
Visual Basic language spec