Bagikan melalui


Ketik Anggota

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:

  • Overridable dan NotOverridable saling eksklusif dan tidak dapat digabungkan.

  • MustOverride menyiratkan Overridable (dan tidak dapat menentukannya) dan tidak dapat dikombinasikan dengan NotOverridable.

  • NotOverridable tidak dapat digabungkan dengan Overridable atau MustOverride dan harus dikombinasikan dengan Overrides.

  • Overrides menyiratkan Overridable (dan tidak dapat menentukannya) dan tidak dapat dikombinasikan dengan MustOverride.

Ada juga batasan tambahan pada metode yang dapat diambil alih:

  • Metode MustOverride mungkin tidak menyertakan isi metode atau End konstruksi, mungkin tidak mengambil alih metode lain, dan hanya dapat muncul di MustInherit kelas.

  • Jika metode menentukan Overrides dan tidak ada metode dasar yang cocok untuk diambil alih, kesalahan waktu kompilasi terjadi. Metode penimpaan mungkin tidak menentukan Shadows.

  • 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 Friend metode di rakitan lain yang tidak memiliki Friend akses harus menentukan Protected (bukan Protected Friend).

  • Private metode mungkin Overridablebukan , , NotOverridableatau MustOverride, juga tidak dapat mengambil alih metode lain.

  • Metode dalam NotInheritable kelas mungkin tidak dideklarasikan Overridable atau MustOverride.

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 ParamArray diberikan untuk bisa berupa ekspresi tunggal dari jenis yang melebar ke ParamArray jenis . Dalam hal ini, ParamArray bertindak 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 .ParamArray Dalam hal ini, pemanggilan membuat instans jenis ParamArray dengan 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 WithEvents pengubah atau MyBase atau MyClassMe kata 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 XEventHandler diperkenalkan. Kelas delegasi berlapis cocok dengan deklarasi metode dan memiliki aksesibilitas yang sama dengan peristiwa. Atribut dalam daftar parameter berlaku untuk parameter kelas delegasi.

  • Private Variabel instans yang di ketik sebagai delegasi, bernama XEvent.

  • Dua metode bernama add_X dan remove_X yang 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 dengan AddHandler deklarasi.

  • Metode bernama remove_X, sesuai dengan RemoveHandler deklarasi.

  • Metode bernama fire_X, sesuai dengan RaiseEvent deklarasi.

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) atau System.TypedEventHandle(Of T, U), dan akan melarang orang lain.

  • Bidang XEvent memiliki jenis System.Runtime.InteropServices.WindowsRuntime.EventRegistrationTokenTable(Of T) di mana T adalah 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 Me atau MyClass.

  • 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 Get aksesor dan Set aksesor. Properti ini dikatakan sebagai properti baca-tulis.

  • Jika properti menentukan pengubah ReadOnly , properti harus memiliki Get aksesor dan mungkin tidak memiliki Set aksesor. 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 memiliki Set aksesor dan mungkin tidak memiliki Get aksesor. 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 daripada Public, , Protected FriendProtected, atau Friend.

  • Friend lebih ketat daripada Protected Friend atau Public.

  • Protected lebih ketat daripada Protected Friend atau Public.

  • Protected Friend lebih ketat daripada Public.

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 Public selalu dan Shared. Pengubah Public dapat dihilangkan dalam konteks di mana pengubah akan diasumsikan.

  • Parameter operator tidak dapat dideklarasikan ByRef, Optional atau ParamArray.

  • 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, Return pernyataan 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 IsTrue dan IsFalse (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 modulo Mod dan 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, Or dan Xor (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, dan Or hanya 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, , dan op_LogicalOr untuk Not, op_LogicalAnd, Anddan Or, 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.