Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Bab ini mencakup sejumlah konsep yang diperlukan untuk memahami semantik bahasa Microsoft Visual Basic. Banyak konsep harus akrab dengan programmer Visual Basic atau programmer C/C++, tetapi definisi presisinya mungkin berbeda.
Deklarasi
Program Visual Basic terdiri dari entitas bernama. Entitas ini diperkenalkan melalui deklarasi dan mewakili "makna" program.
Di tingkat atas, namespace adalah entitas yang mengatur entitas lain, seperti namespace dan jenis berlapis. Jenis adalah entitas yang menjelaskan nilai dan menentukan kode yang dapat dieksekusi. Jenis mungkin berisi jenis berlapis dan jenis anggota. Anggota jenis adalah konstanta, variabel, metode, operator, properti, peristiwa, nilai enumerasi, dan konstruktor.
Entitas yang dapat berisi entitas lain mendefinisikan ruang deklarasi. Entitas diperkenalkan ke dalam ruang deklarasi baik melalui deklarasi atau warisan; ruang deklarasi yang berisi disebut konteks deklarasi entitas. Mendeklarasikan entitas dalam ruang deklarasi pada gilirannya menentukan ruang deklarasi baru yang dapat berisi deklarasi entitas berlapis lebih lanjut; dengan demikian, deklarasi dalam suatu program membentuk hierarki ruang deklarasi.
Kecuali dalam kasus anggota jenis kelebihan beban, tidak valid untuk deklarasi untuk memperkenalkan entitas bernama yang identik dengan jenis yang sama ke dalam konteks deklarasi yang sama. Selain itu, ruang deklarasi mungkin tidak pernah berisi berbagai jenis entitas dengan nama yang sama; misalnya, ruang deklarasi mungkin tidak pernah berisi variabel dan metode dengan nama yang sama.
Nota. Mungkin dalam bahasa lain dapat membuat ruang deklarasi yang berisi berbagai jenis entitas dengan nama yang sama (misalnya, jika bahasa peka huruf besar/kecil dan memungkinkan deklarasi yang berbeda berdasarkan casing). Dalam situasi itu, entitas yang paling dapat diakses dianggap terikat dengan nama tersebut; jika lebih dari satu jenis entitas paling dapat diakses, maka namanya ambigu.
Public lebih mudah diakses daripada Protected Friend, Protected Friend lebih mudah diakses daripada Protected atau Friend, dan Protected atau Friend lebih mudah diakses daripada Private.
Ruang deklarasi namespace layanan "terbuka berakhir," sehingga dua deklarasi namespace dengan nama yang sepenuhnya memenuhi syarat yang sama berkontribusi pada ruang deklarasi yang sama. Dalam contoh di bawah ini, dua deklarasi namespace berkontribusi pada ruang deklarasi yang sama, dalam hal ini mendeklarasikan dua kelas dengan nama Data.Customer yang sepenuhnya memenuhi syarat dan Data.Order:
Namespace Data
Class Customer
End Class
End Namespace
Namespace Data
Class Order
End Class
End Namespace
Karena kedua deklarasi berkontribusi pada ruang deklarasi yang sama, kesalahan waktu kompilasi akan terjadi jika masing-masing berisi deklarasi kelas dengan nama yang sama.
Kelebihan Beban dan Tanda Tangan
Satu-satunya cara untuk mendeklarasikan entitas bernama identik dari jenis yang sama dalam ruang deklarasi adalah melalui kelebihan beban. Hanya metode, operator, konstruktor instans, dan properti yang mungkin kelebihan beban.
Anggota jenis yang kelebihan beban harus memiliki tanda tangan unik. Tanda tangan anggota jenis terdiri dari jumlah parameter jenis, dan jumlah dan jenis parameter anggota. Operator konversi juga menyertakan jenis pengembalian operator dalam tanda tangan.
Berikut ini bukan bagian dari tanda tangan anggota, dan karenanya tidak dapat kelebihan beban pada:
Pengubah untuk anggota jenis (misalnya,
SharedatauPrivate).Pengubah ke parameter (misalnya,
ByValatauByRef).Nama parameter.
Jenis pengembalian metode atau operator (kecuali untuk operator konversi) atau jenis elemen properti.
Batasan pada parameter jenis.
Contoh berikut menunjukkan sekumpulan deklarasi metode yang kelebihan beban bersama dengan tanda tangannya. Deklarasi ini tidak akan valid karena beberapa deklarasi metode memiliki tanda tangan yang identik.
Interface ITest
Sub F1() ' Signature is ().
Sub F2(x As Integer) ' Signature is (Integer).
Sub F3(ByRef x As Integer) ' Signature is (Integer).
Sub F4(x As Integer, y As Integer) ' Signature is (Integer, Integer).
Function F5(s As String) As Integer ' Signature is (String).
Function F6(x As Integer) As Integer ' Signature is (Integer).
Sub F7(a() As String) ' Signature is (String()).
Sub F8(ParamArray a() As String) ' Signature is (String()).
Sub F9(Of T)() ' Signature is !1().
Sub F10(Of T, U)(x As T, y As U) ' Signature is !2(!1, !2)
Sub F11(Of U, T)(x As T, y As U) ' Signature is !2(!2, !1)
Sub F12(Of T)(x As T) ' Signature is !1(!1)
Sub F13(Of T As IDisposable)(x As T) ' Signature is !1(!1)
End Interface
Valid untuk menentukan jenis generik yang mungkin berisi anggota dengan tanda tangan identik berdasarkan argumen jenis yang disediakan. Aturan resolusi kelebihan beban digunakan untuk mencoba dan memisahkan antara kelebihan beban tersebut, meskipun mungkin ada situasi di mana tidak mungkin untuk membedakan. Contohnya:
Class C(Of T)
Sub F(x As Integer)
End Sub
Sub F(x As T)
End Sub
Sub G(Of U)(x As T, y As U)
End Sub
Sub G(Of U)(x As U, y As T)
End Sub
End Class
Module Test
Sub Main()
Dim x As New C(Of Integer)
x.F(10) ' Calls C(Of T).F(Integer)
x.G(Of Integer)(10, 10) ' Error: Can't choose between overloads
End Sub
End Module
Ruang Lingkup
Cakupan nama entitas adalah kumpulan semua ruang deklarasi di mana dimungkinkan untuk merujuk ke nama tersebut tanpa kualifikasi. Secara umum, cakupan nama entitas adalah seluruh konteks deklarasinya; namun, deklarasi entitas mungkin berisi deklarasi entitas berlapis dengan nama yang sama. Dalam hal ini, entitas berlapis bayangan, atau bersembunyi, entitas luar, dan akses ke entitas ber bayangan hanya dimungkinkan melalui kualifikasi.
Bayangan melalui berlapis terjadi di namespace layanan atau jenis yang disarangkan dalam namespace, dalam jenis yang disarangkan dalam jenis lain, dan di badan anggota jenis. Bayangan melalui bersarangnya deklarasi selalu terjadi secara implisit; tidak diperlukan sintaks eksplisit.
Dalam contoh berikut, dalam F metode , variabel i instans di bayangan oleh variabel ilokal , tetapi dalam G metode , i masih mengacu pada variabel instans.
Class Test
Private i As Integer = 0
Sub F()
Dim i As Integer = 1
End Sub
Sub G()
i = 1
End Sub
End Class
Ketika nama dalam cakupan dalam menyembunyikan nama dalam cakupan luar, nama tersebut membayangi semua kejadian yang kelebihan beban nama tersebut. Dalam contoh berikut, panggilan F(1) memanggil F yang dinyatakan di karena semua kejadian F luar disembunyikan Inner oleh deklarasi bagian dalam. Untuk alasan yang sama, panggilan F("Hello") dalam kesalahan.
Class Outer
Shared Sub F(i As Integer)
End Sub
Shared Sub F(s As String)
End Sub
Class Inner
Shared Sub F(l As Long)
End Sub
Sub G()
F(1) ' Invokes Outer.Inner.F.
F("Hello") ' Error.
End Sub
End Class
End Class
Pewarisan
Hubungan warisan adalah salah satu jenis (jenis turunan ) yang berasal dari jenis lain (jenis dasar ), sehingga ruang deklarasi jenis turunan secara implisit berisi anggota jenis non-konstruktor yang dapat diakses dan jenis berlapis dari jenis dasarnya. Dalam contoh berikut, kelas A adalah kelas dasar dari B, dan B berasal dari A.
Class A
End Class
Class B
Inherits A
End Class
Karena A tidak secara eksplisit menentukan kelas dasar, kelas dasarnya secara Objectimplisit .
Berikut ini adalah aspek penting dari warisan:
Warisan bersifat transitif. Jika tipe C berasal dari tipe B, dan tipe B berasal dari tipe A, tipe C mewarisi jenis anggota yang dinyatakan dalam tipe B serta anggota jenis yang dinyatakan dalam tipe A.
Jenis turunan meluas, tetapi tidak dapat mempersempit, jenis dasarnya. Jenis turunan dapat menambahkan anggota jenis baru, dan dapat membayangi anggota jenis yang diwariskan, tetapi tidak dapat menghapus definisi anggota jenis yang diwariskan.
Karena instans jenis berisi semua anggota jenis jenis dasarnya, konversi selalu ada dari jenis turunan ke jenis dasarnya.
Semua jenis harus memiliki jenis dasar, kecuali untuk jenis
Object. Dengan demikian,Objectadalah jenis dasar utama dari semua jenis, dan semua jenis dapat dikonversi ke dalamnya.Edaran dalam derivasi tidak diizinkan. Artinya, ketika jenis
Bberasal dari jenisA, itu adalah kesalahan untuk jenisAuntuk memperoleh secara langsung atau tidak langsung dari jenisB.Jenis mungkin tidak secara langsung atau tidak langsung berasal dari jenis yang berlapis di dalamnya.
Contoh berikut menghasilkan kesalahan waktu kompilasi karena kelas secara melingkar bergantung satu sama lain.
Class A
Inherits B
End Class
Class B
Inherits C
End Class
Class C
Inherits A
End Class
Contoh berikut juga menghasilkan kesalahan waktu kompilasi karena B secara tidak langsung berasal dari kelas C berlapisnya melalui kelas A.
Class A
Inherits B.C
End Class
Class B
Inherits A
Public Class C
End Class
End Class
Contoh berikutnya tidak menghasilkan kesalahan karena kelas A tidak berasal dari kelas B.
Class A
Class B
Inherits A
End Class
End Class
Kelas MustInherit dan NotInheritable
Kelas MustInherit adalah jenis yang tidak lengkap yang hanya dapat bertindak sebagai jenis dasar. Kelas MustInherit tidak dapat diinstansiasi, jadi ini adalah kesalahan untuk menggunakan New operator pada satu kelas. Valid untuk mendeklarasikan variabel MustInherit kelas; variabel tersebut MustInherit hanya dapat ditetapkan Nothing atau nilai yang berasal dari kelas.
Ketika kelas reguler berasal dari MustInherit kelas , kelas reguler harus mengambil alih semua anggota yang diwariskan MustOverride . Contohnya:
MustInherit Class A
Public MustOverride Sub F()
End Class
MustInherit Class B
Inherits A
Public Sub G()
End Sub
End Class
Class C
Inherits B
Public Overrides Sub F()
End Sub
End Class
A Kelas MustInherit memperkenalkan MustOverride metode F. Kelas B memperkenalkan metode Gtambahan , tetapi tidak menyediakan implementasi .F Oleh karena itu kelas B juga harus dinyatakan MustInherit. Kelas C mengambil alih F dan memberikan implementasi aktual. Karena tidak ada anggota terutang MustOverride di kelas C, tidak diharuskan untuk menjadi MustInherit.
Kelas NotInheritable adalah kelas tempat kelas lain tidak dapat diturunkan.
NotInheritable kelas terutama digunakan untuk mencegah derivasi yang tidak diinginkan.
Dalam contoh ini, kelas B dalam kesalahan karena mencoba untuk berasal dari NotInheritable kelas A. Kelas tidak dapat ditandai dan MustInheritNotInheritable.
NotInheritable Class A
End Class
Class B
' Error, a class cannot derive from a NotInheritable class.
Inherits A
End Class
Antarmuka dan Beberapa Warisan
Tidak seperti jenis lain, yang hanya berasal dari satu jenis dasar, antarmuka dapat berasal dari beberapa antarmuka dasar. Karena itu, antarmuka dapat mewarisi anggota jenis bernama identik dari antarmuka dasar yang berbeda. Dalam kasus seperti itu, nama yang diwariskan perkalian tidak tersedia di antarmuka turunan, dan mengacu pada salah satu anggota jenis tersebut melalui antarmuka turunan menyebabkan kesalahan waktu kompilasi, terlepas dari tanda tangan atau kelebihan beban. Sebagai gantinya, anggota jenis yang berkonflik harus dirujuk melalui nama antarmuka dasar.
Dalam contoh berikut, dua pernyataan pertama menyebabkan kesalahan waktu kompilasi karena anggota Count yang diwariskan perkalian tidak tersedia di antarmuka IListCounter:
Interface IList
Property Count() As Integer
End Interface
Interface ICounter
Sub Count(i As Integer)
End Interface
Interface IListCounter
Inherits IList
Inherits ICounter
End Interface
Module Test
Sub F(x As IListCounter)
x.Count(1) ' Error, Count is not available.
x.Count = 1 ' Error, Count is not available.
CType(x, IList).Count = 1 ' Ok, invokes IList.Count.
CType(x, ICounter).Count(1) ' Ok, invokes ICounter.Count.
End Sub
End Module
Seperti yang diilustrasikan oleh contoh, ambiguitas diselesaikan dengan mentransmisikan x ke jenis antarmuka dasar yang sesuai. Cast tersebut tidak memiliki biaya run-time; mereka hanya terdiri dari melihat instans sebagai jenis yang kurang diturunkan pada waktu kompilasi.
Ketika anggota jenis tunggal diwarisi dari antarmuka dasar yang sama melalui beberapa jalur, anggota jenis diperlakukan seolah-olah hanya diwariskan sekali. Dengan kata lain, antarmuka turunan hanya berisi satu instans dari setiap anggota jenis yang diwarisi dari antarmuka dasar tertentu. Contohnya:
Interface IBase
Sub F(i As Integer)
End Interface
Interface ILeft
Inherits IBase
End Interface
Interface IRight
Inherits IBase
End Interface
Interface IDerived
Inherits ILeft, IRight
End Interface
Class Derived
Implements IDerived
' Only have to implement F once.
Sub F(i As Integer) Implements IDerived.F
End Sub
End Class
Jika nama anggota jenis dibayangi dalam satu jalur melalui hierarki pewarisan, maka nama dibayangi di semua jalur. Dalam contoh berikut, IBase.F anggota di bayangan oleh ILeft.F anggota, tetapi tidak di bayangan di IRight:
Interface IBase
Sub F(i As Integer)
End Interface
Interface ILeft
Inherits IBase
Shadows Sub F(i As Integer)
End Interface
Interface IRight
Inherits IBase
Sub G()
End Interface
Interface IDerived
Inherits ILeft, IRight
End Interface
Class Test
Sub H(d As IDerived)
d.F(1) ' Invokes ILeft.F.
CType(d, IBase).F(1) ' Invokes IBase.F.
CType(d, ILeft).F(1) ' Invokes ILeft.F.
CType(d, IRight).F(1) ' Invokes IBase.F.
End Sub
End Class
Pemanggilan d.F(1) memilih ILeft.F, meskipun IBase.F tampaknya tidak dibayangi di jalur akses yang mengarah melalui IRight. Karena jalur akses dari IDerived ke IBaseILeft bayangan IBase.F, anggota juga di bayangan di jalur akses dari IDerived ke IRight .IBase
Bayangan
Jenis turunan membayangi nama anggota jenis yang diwariskan dengan mendeklarasikan ulang. Membayangi nama tidak menghapus anggota jenis yang diwariskan dengan nama tersebut; itu hanya membuat semua anggota jenis yang diwariskan dengan nama itu tidak tersedia di kelas turunan. Deklarasi bayangan mungkin jenis entitas apa pun.
Entitas daripada yang dapat kelebihan beban dapat memilih salah satu dari dua bentuk bayangan.
Bayangan berdasarkan nama ditentukan menggunakan Shadows kata kunci. Entitas yang bayangan berdasarkan nama menyembunyikan semuanya berdasarkan nama tersebut di kelas dasar, termasuk semua kelebihan beban.
Bayangan berdasarkan nama dan tanda tangan ditentukan menggunakan Overloads kata kunci. Entitas yang membayangi berdasarkan nama dan tanda tangan menyembunyikan semuanya dengan nama tersebut dengan tanda tangan yang sama dengan entitas. Contohnya:
Class Base
Sub F()
End Sub
Sub F(i As Integer)
End Sub
Sub G()
End Sub
Sub G(i As Integer)
End Sub
End Class
Class Derived
Inherits Base
' Only hides F(Integer).
Overloads Sub F(i As Integer)
End Sub
' Hides G() and G(Integer).
Shadows Sub G(i As Integer)
End Sub
End Class
Module Test
Sub Main()
Dim x As New Derived()
x.F() ' Calls Base.F().
x.G() ' Error: Missing parameter.
End Sub
End Module
Membayangi metode dengan argumen berdasarkan ParamArray nama dan tanda tangan hanya menyembunyikan tanda tangan individual, tidak semua kemungkinan tanda tangan yang diperluas. Ini berlaku bahkan jika tanda tangan metode bayangan cocok dengan tanda tangan yang tidak tertandingi dari metode ber bayangan. Contoh berikut:
Class Base
Sub F(ParamArray x() As Integer)
Console.WriteLine("Base")
End Sub
End Class
Class Derived
Inherits Base
Overloads Sub F(x() As Integer)
Console.WriteLine("Derived")
End Sub
End Class
Module Test
Sub Main
Dim d As New Derived()
d.F(10)
End Sub
End Module
Basemencetak , meskipun Derived.F memiliki tanda tangan yang sama dengan bentuk yang tidak terlampaui dari Base.F.
Sebaliknya, metode dengan ParamArray argumen hanya membayangi metode dengan tanda tangan yang sama, tidak semua kemungkinan tanda tangan yang diperluas. Contoh berikut:
Class Base
Sub F(x As Integer)
Console.WriteLine("Base")
End Sub
End Class
Class Derived
Inherits Base
Overloads Sub F(ParamArray x() As Integer)
Console.WriteLine("Derived")
End Sub
End Class
Module Test
Sub Main()
Dim d As New Derived()
d.F(10)
End Sub
End Module
Basemencetak , meskipun Derived.F memiliki formulir yang diperluas yang memiliki tanda tangan yang sama dengan Base.F.
Metode atau properti bayangan yang tidak menentukan Shadows atau Overloads mengasumsikan Overloads apakah metode atau properti dinyatakan Overrides, Shadows jika tidak. Jika satu anggota sekumpulan entitas yang kelebihan beban menentukan Shadows kata kunci atau Overloads , semuanya harus menentukannya. Kata Shadows kunci dan Overloads tidak dapat ditentukan secara bersamaan. Baik Shadows maupun Overloads tidak dapat ditentukan dalam modul standar; anggota dalam modul standar secara implisit membayangi anggota yang diwarisi dari Object.
Ini valid untuk membayangi nama anggota jenis yang telah diwariskan perkalian melalui pewarisan antarmuka (dan yang tidak tersedia), sehingga membuat nama tersedia di antarmuka turunan.
Contohnya:
Interface ILeft
Sub F()
End Interface
Interface IRight
Sub F()
End Interface
Interface ILeftRight
Inherits ILeft, IRight
Shadows Sub F()
End Interface
Module Test
Sub G(i As ILeftRight)
i.F() ' Calls ILeftRight.F.
CType(i, ILeft).F() ' Calls ILeft.F.
CType(i, IRight).F() ' Calls IRight.F.
End Sub
End Module
Karena metode diizinkan untuk membayangi metode yang diwariskan, dimungkinkan bagi kelas untuk berisi beberapa Overridable metode dengan tanda tangan yang sama. Ini tidak menghadirkan masalah ambiguitas, karena hanya metode yang paling turunan yang terlihat. Dalam contoh berikut, C kelas dan D berisi dua Overridable metode dengan tanda tangan yang sama:
Class A
Public Overridable Sub F()
Console.WriteLine("A.F")
End Sub
End Class
Class B
Inherits A
Public Overrides Sub F()
Console.WriteLine("B.F")
End Sub
End Class
Class C
Inherits B
Public Shadows Overridable Sub F()
Console.WriteLine("C.F")
End Sub
End Class
Class D
Inherits C
Public Overrides Sub F()
Console.WriteLine("D.F")
End Sub
End Class
Module Test
Sub Main()
Dim d As New D()
Dim a As A = d
Dim b As B = d
Dim c As C = d
a.F()
b.F()
c.F()
d.F()
End Sub
End Module
Ada dua Overridable metode di sini: satu diperkenalkan oleh kelas A dan yang diperkenalkan oleh kelas C. Metode yang diperkenalkan oleh kelas C menyembunyikan metode yang diwariskan dari kelas A. Dengan demikian, Overrides deklarasi di kelas D mengambil alih metode yang diperkenalkan oleh kelas C, dan tidak mungkin bagi kelas D untuk mengambil alih metode yang diperkenalkan oleh kelas A. Contoh menghasilkan output:
B.F
B.F
D.F
D.F
Dimungkinkan untuk memanggil metode tersembunyi Overridable dengan mengakses instans kelas D melalui jenis yang kurang diturunkan di mana metode tidak disembunyikan.
Tidak valid untuk membayangi MustOverride metode, karena dalam banyak kasus ini akan membuat kelas tidak dapat digunakan. Contohnya:
MustInherit Class Base
Public MustOverride Sub F()
End Class
MustInherit Class Derived
Inherits Base
Public Shadows Sub F()
End Sub
End Class
Class MoreDerived
Inherits Derived
' Error: MustOverride method Base.F is not overridden.
End Class
Dalam hal ini, kelas MoreDerived diperlukan untuk mengambil MustOverride alih metode Base.F, tetapi karena bayangan Base.Fkelas Derived , ini tidak mungkin. Tidak ada cara untuk menyatakan keturunan yang valid dari Derived.
Berbeda dengan bayangan nama dari cakupan luar, membayangi nama yang dapat diakses dari cakupan yang diwariskan menyebabkan peringatan dilaporkan, seperti dalam contoh berikut:
Class Base
Public Sub F()
End Sub
Private Sub G()
End Sub
End Class
Class Derived
Inherits Base
Public Sub F() ' Warning: shadowing an inherited name.
End Sub
Public Sub G() ' No warning, Base.G is not accessible here.
End Sub
End Class
Deklarasi metode F di kelas Derived menyebabkan peringatan dilaporkan. Membayangi nama yang diwariskan secara khusus bukan kesalahan, karena itu akan menghalangi evolusi terpisah dari kelas dasar. Misalnya, situasi di atas mungkin muncul karena versi kelas Base yang lebih baru memperkenalkan metode F yang tidak ada di versi kelas yang lebih lama. Jika situasi di atas adalah kesalahan, setiap perubahan yang dilakukan pada kelas dasar di pustaka kelas versi terpisah berpotensi menyebabkan kelas turunan menjadi tidak valid.
Peringatan yang disebabkan oleh bayangan nama yang diwariskan dapat dihilangkan melalui penggunaan Shadows pengubah atau Overloads :
Class Base
Public Sub F()
End Sub
End Class
Class Derived
Inherits Base
Public Shadows Sub F() 'OK.
End Sub
End Class
Pengubah Shadows menunjukkan niat untuk membayangi anggota yang diwariskan. Ini bukan kesalahan untuk menentukan Shadows pengubah atau Overloads jika tidak ada nama anggota jenis untuk bayangan.
Deklarasi anggota baru membayangi anggota yang diwariskan hanya dalam lingkup anggota baru, seperti dalam contoh berikut:
Class Base
Public Shared Sub F()
End Sub
End Class
Class Derived
Inherits Base
Private Shared Shadows Sub F() ' Shadows Base.F in class Derived only.
End Sub
End Class
Class MoreDerived
Inherits Derived
Shared Sub G()
F() ' Invokes Base.F.
End Sub
End Class
Dalam contoh di atas, deklarasi metode F di kelas Derived membayangi metode F yang diwarisi dari kelas Base, tetapi karena metode F baru di kelas Derived memiliki Private akses, cakupannya tidak meluas ke kelas MoreDerived. Dengan demikian, panggilan F() masuk MoreDerived.G valid dan akan memanggil Base.F. Dalam kasus anggota jenis yang kelebihan beban, seluruh set anggota jenis yang kelebihan beban diperlakukan seolah-olah mereka semua memiliki akses yang paling permisif untuk tujuan bayangan.
Class Base
Public Sub F()
End Sub
End Class
Class Derived
Inherits Base
Private Shadows Sub F()
End Sub
Public Shadows Sub F(i As Integer)
End Sub
End Class
Class MoreDerived
Inherits Derived
Public Sub G()
F() ' Error. No accessible member with this signature.
End Sub
End Class
Dalam contoh ini, meskipun deklarasi F() masuk dinyatakan Derived dengan Private akses, kelebihan beban dinyatakan F(Integer) dengan Public akses. Oleh karena itu, untuk tujuan membayangi, nama F di Derived diperlakukan seolah-olah itu Public, sehingga kedua metode membayangi F dalam Base.
Pelaksanaan
Hubungan implementasi ada ketika jenis menyatakan bahwa ia mengimplementasikan antarmuka dan jenis mengimplementasikan semua anggota jenis antarmuka. Jenis yang mengimplementasikan antarmuka tertentu dapat dikonversi ke antarmuka tersebut. Antarmuka tidak dapat dibuat, tetapi valid untuk mendeklarasikan variabel antarmuka; variabel tersebut hanya dapat ditetapkan nilai yang merupakan kelas yang mengimplementasikan antarmuka. Contohnya:
Interface ITestable
Function Test(value As Byte) As Boolean
End Interface
Class TestableClass
Implements ITestable
Function Test(value As Byte) As Boolean Implements ITestable.Test
Return value > 128
End Function
End Class
Module Test
Sub F()
Dim x As ITestable = New TestableClass
Dim b As Boolean
b = x.Test(34)
End Sub
End Module
Jenis yang mengimplementasikan antarmuka dengan anggota jenis multiply-inherited masih harus menerapkan metode tersebut, meskipun tidak dapat diakses langsung dari antarmuka turunan yang diterapkan. Contohnya:
Interface ILeft
Sub Test()
End Interface
Interface IRight
Sub Test()
End Interface
Interface ILeftRight
Inherits ILeft, IRight
End Interface
Class LeftRight
Implements ILeftRight
' Has to reference ILeft explicitly.
Sub TestLeft() Implements ILeft.Test
End Sub
' Has to reference IRight explicitly.
Sub TestRight() Implements IRight.Test
End Sub
' Error: Test is not available in ILeftRight.
Sub TestLeftRight() Implements ILeftRight.Test
End Sub
End Class
Bahkan MustInherit kelas harus menyediakan implementasi semua anggota antarmuka yang diimplementasikan; namun, mereka dapat menunda implementasi metode ini dengan mendeklarasikannya sebagai MustOverride. Contohnya:
Interface ITest
Sub Test1()
Sub Test2()
End Interface
MustInherit Class TestBase
Implements ITest
' Provides an implementation.
Sub Test1() Implements ITest.Test1
End Sub
' Defers implementation.
MustOverride Sub Test2() Implements ITest.Test2
End Class
Class TestDerived
Inherits TestBase
' Have to implement MustOverride method.
Overrides Sub Test2()
End Sub
End Class
Jenis dapat memilih untuk mengimplementasikan ulang antarmuka yang diterapkan jenis dasarnya. Untuk mengimplementasikan ulang antarmuka, jenis harus secara eksplisit menyatakan bahwa antarmuka mengimplementasikan antarmuka. Jenis yang mengimplementasikan ulang antarmuka dapat memilih untuk mengimplementasikan ulang hanya beberapa, tetapi tidak semua, dari anggota antarmuka -- anggota apa pun yang tidak diimplementasikan ulang terus menggunakan implementasi jenis dasar. Contohnya:
Class TestBase
Implements ITest
Sub Test1() Implements ITest.Test1
Console.WriteLine("TestBase.Test1")
End Sub
Sub Test2() Implements ITest.Test2
Console.WriteLine("TestBase.Test2")
End Sub
End Class
Class TestDerived
Inherits TestBase
Implements ITest ' Required to re-implement
Sub DerivedTest1() Implements ITest.Test1
Console.WriteLine("TestDerived.DerivedTest1")
End Sub
End Class
Module Test
Sub Main()
Dim Test As ITest = New TestDerived()
Test.Test1()
Test.Test2()
End Sub
End Module
Contoh ini mencetak:
TestDerived.DerivedTest1
TestBase.Test2
Ketika jenis turunan mengimplementasikan antarmuka yang antarmuka dasarnya diimplementasikan oleh jenis dasar jenis turunan, jenis turunan dapat memilih untuk hanya mengimplementasikan anggota jenis antarmuka yang belum diimplementasikan oleh jenis dasar. Contohnya:
Interface IBase
Sub Base()
End Interface
Interface IDerived
Inherits IBase
Sub Derived()
End Interface
Class Base
Implements IBase
Public Sub Base() Implements IBase.Base
End Sub
End Class
Class Derived
Inherits Base
Implements IDerived
' Required: IDerived.Derived not implemented by Base.
Public Sub Derived() Implements IDerived.Derived
End Sub
End Class
Metode antarmuka juga dapat diimplementasikan menggunakan metode yang dapat diganti dalam jenis dasar. Dalam hal ini, jenis turunan juga dapat mengambil alih metode yang dapat diambil alih dan mengubah implementasi antarmuka. Contohnya:
Class Base
Implements ITest
Public Sub Test1() Implements ITest.Test1
Console.WriteLine("TestBase.Test1")
End Sub
Public Overridable Sub Test2() Implements ITest.Test2
Console.WriteLine("TestBase.Test2")
End Sub
End Class
Class Derived
Inherits Base
' Overrides base implementation.
Public Overrides Sub Test2()
Console.WriteLine("TestDerived.Test2")
End Sub
End Class
Metode Penerapan
Jenis mengimplementasikan jenis anggota antarmuka yang diimplementasikan dengan menyediakan metode dengan klausa Implements . Dua anggota jenis harus memiliki jumlah parameter yang sama, semua jenis dan pengubah parameter harus cocok, termasuk nilai default parameter opsional, jenis pengembalian harus cocok, dan semua batasan pada parameter metode harus cocok. Contohnya:
Interface ITest
Sub F(ByRef x As Integer)
Sub G(Optional y As Integer = 20)
Sub H(Paramarray z() As Integer)
End Interface
Class Test
Implements ITest
' Error: ByRef/ByVal mismatch.
Sub F(x As Integer) Implements ITest.F
End Sub
' Error: Defaults do not match.
Sub G(Optional y As Integer = 10) Implements ITest.G
End Sub
' Error: Paramarray does not match.
Sub H(z() As Integer) Implements ITest.H
End Sub
End Class
Satu metode dapat mengimplementasikan sejumlah anggota jenis antarmuka jika semuanya memenuhi kriteria di atas. Contohnya:
Interface ITest
Sub F(i As Integer)
Sub G(i As Integer)
End Interface
Class Test
Implements ITest
Sub F(i As Integer) Implements ITest.F, ITest.G
End Sub
End Class
Saat menerapkan metode dalam antarmuka generik, metode penerapan harus menyediakan argumen jenis yang sesuai dengan parameter jenis antarmuka. Contohnya:
Interface I1(Of U, V)
Sub M(x As U, y As List(Of V))
End Interface
Class C1(Of W, X)
Implements I1(Of W, X)
' W corresponds to U and X corresponds to V
Public Sub M(x As W, y As List(Of X)) Implements I1(Of W, X).M
End Sub
End Class
Class C2
Implements I1(Of String, Integer)
' String corresponds to U and Integer corresponds to V
Public Sub M(x As String, y As List(Of Integer)) _
Implements I1(Of String, Integer).M
End Sub
End Class
Perhatikan bahwa ada kemungkinan bahwa antarmuka generik mungkin tidak dapat diimplementasikan untuk beberapa set argumen jenis.
Interface I1(Of T, U)
Sub S1(x As T)
Sub S1(y As U)
End Interface
Class C1
' Unable to implement because I1.S1 has two identical signatures
Implements I1(Of Integer, Integer)
End Class
Polimorfisme
Polimorfisme memberikan kemampuan untuk memvariasikan implementasi metode atau properti. Dengan polimorfisme, metode atau properti yang sama dapat melakukan tindakan yang berbeda tergantung pada jenis run-time instans yang memanggilnya. Metode atau properti yang polimorfik disebut dapat diganti. Sebaliknya, implementasi metode atau properti yang tidak dapat ditimpa invariant; implementasinya sama apakah metode atau properti dipanggil pada instans kelas di mana ia dideklarasikan atau instans kelas turunan. Ketika metode atau properti yang tidak dapat diambil alih dipanggil, jenis waktu kompilasi instans adalah faktor penentu. Contohnya:
Class Base
Public Overridable Property X() As Integer
Get
End Get
Set
End Set
End Property
End Class
Class Derived
Inherits Base
Public Overrides Property X() As Integer
Get
End Get
Set
End Set
End Property
End Class
Module Test
Sub F()
Dim Z As Base
Z = New Base()
Z.X = 10 ' Calls Base.X
Z = New Derived()
Z.X = 10 ' Calls Derived.X
End Sub
End Module
Metode yang dapat MustOverridediambil alih mungkin juga , yang berarti tidak menyediakan isi metode dan harus ditimpa.
MustOverride metode hanya diperbolehkan di MustInherit kelas.
Dalam contoh berikut, kelas Shape menentukan gagasan abstrak dari objek bentuk geometris yang dapat melukis dirinya sendiri:
MustInherit Public Class Shape
Public MustOverride Sub Paint(g As Graphics, r As Rectangle)
End Class
Public Class Ellipse
Inherits Shape
Public Overrides Sub Paint(g As Graphics, r As Rectangle)
g.drawEllipse(r)
End Sub
End Class
Public Class Box
Inherits Shape
Public Overrides Sub Paint(g As Graphics, r As Rectangle)
g.drawRect(r)
End Sub
End Class
Metode Paint ini MustOverride karena tidak ada implementasi default yang bermakna. Kelas Ellipse dan Box adalah implementasi konkret Shape . Karena kelas-kelas ini bukan MustInherit, kelas ini Paint diperlukan untuk mengambil alih metode dan memberikan implementasi aktual.
Ini adalah kesalahan untuk akses dasar untuk mereferensikan MustOverride metode, seperti yang ditunjukkan contoh berikut:
MustInherit Class A
Public MustOverride Sub F()
End Class
Class B
Inherits A
Public Overrides Sub F()
MyBase.F() ' Error, MyBase.F is MustOverride.
End Sub
End Class
Kesalahan dilaporkan untuk MyBase.F() pemanggilan karena mereferensikan MustOverride metode.
Metode Penimpaan
Jenis dapat mengambil alih metode yang dapat diambil alih yang diwariskan dengan mendeklarasikan metode dengan nama yang sama dan , tanda tangan, dan menandai deklarasi dengan pengubah Overrides . Ada persyaratan tambahan tentang metode penimpaan, yang tercantum di bawah ini.
Overridable Sedangkan deklarasi metode memperkenalkan metode baru, Overrides deklarasi metode menggantikan implementasi metode yang diwariskan.
Metode penimpaan dapat dinyatakan NotOverridable, yang mencegah pengesampingan lebih lanjut dari metode dalam jenis turunan. Akibatnya, NotOverridable metode menjadi tidak dapat diganti di kelas turunan lebih lanjut.
Pertimbangkan contoh berikut:
Class A
Public Overridable Sub F()
Console.WriteLine("A.F")
End Sub
Public Overridable Sub G()
Console.WriteLine("A.G")
End Sub
End Class
Class B
Inherits A
Public Overrides NotOverridable Sub F()
Console.WriteLine("B.F")
End Sub
Public Overrides Sub G()
Console.WriteLine("B.G")
End Sub
End Class
Class C
Inherits B
Public Overrides Sub G()
Console.WriteLine("C.G")
End Sub
End Class
Dalam contoh, kelas B menyediakan dua Overrides metode: metode F yang memiliki NotOverridable pengubah dan metode G yang tidak. Penggunaan pengubah NotOverridable mencegah kelas C mengambil alih metode Flebih lanjut .
Metode penimpaan juga dapat dinyatakan MustOverride, bahkan jika metode penimpaannya tidak dinyatakan MustOverride. Ini mengharuskan MustInherit kelas yang berisi dideklarasikan dan bahwa kelas turunan lebih lanjut yang tidak dinyatakan MustInherit harus mengambil alih metode . Contohnya:
Class A
Public Overridable Sub F()
Console.WriteLine("A.F")
End Sub
End Class
MustInherit Class B
Inherits A
Public Overrides MustOverride Sub F()
End Class
Dalam contoh, kelas B mengambil alih A.F dengan MustOverride metode . Ini berarti bahwa setiap kelas yang berasal dari B harus mengambil alih F, kecuali mereka dinyatakan MustInherit juga.
Kesalahan waktu kompilasi terjadi kecuali semua hal berikut ini benar dari metode penimpaan:
- Konteks deklarasi berisi satu metode yang diwariskan yang dapat diakses dengan tanda tangan dan jenis pengembalian yang sama (jika ada) sebagai metode penimpaan.
- Metode yang diwariskan yang ditimpa dapat diambil alih. Dengan kata lain, metode warisan yang ditimpa bukan
SharedatauNotOverridable. - Domain aksesibilitas metode yang dideklarasikan sama dengan domain aksesibilitas metode yang diwariskan yang ditimpa. Ada satu pengecualian:
Protected Friendmetode harus ditimpa olehProtectedmetode jika metode lain berada di rakitan lain yang tidak dapatFrienddiakses oleh metode penimpaan. - Parameter metode penimpaan cocok dengan parameter metode yang ditimpa sehubungan dengan penggunaan
ByValpengubah , ,ByRefParamArray,danOptional, termasuk nilai yang disediakan untuk parameter opsional. - Parameter jenis metode penimpaan cocok dengan parameter jenis metode yang ditimpa sehubungan dengan batasan jenis.
Saat mengambil alih metode dalam jenis generik dasar, metode penimpaan harus menyediakan argumen jenis yang sesuai dengan parameter jenis dasar. Contohnya:
Class Base(Of U, V)
Public Overridable Sub M(x As U, y As List(Of V))
End Sub
End Class
Class Derived(Of W, X)
Inherits Base(Of W, X)
' W corresponds to U and X corresponds to V
Public Overrides Sub M(x As W, y As List(Of X))
End Sub
End Class
Class MoreDerived
Inherits Derived(Of String, Integer)
' String corresponds to U and Integer corresponds to V
Public Overrides Sub M(x As String, y As List(Of Integer))
End Sub
End Class
Perhatikan bahwa ada kemungkinan bahwa metode yang dapat diambil alih di kelas generik mungkin tidak dapat ditimpa untuk beberapa set argumen jenis. Jika metode dinyatakan , ini berarti bahwa beberapa rantai warisan mungkin tidak dimungkinkan MustOverride. Contohnya:
MustInherit Class Base(Of T, U)
Public MustOverride Sub S1(x As T)
Public MustOverride Sub S1(y As U)
End Class
Class Derived
Inherits Base(Of Integer, Integer)
' Error: Can't override both S1's at once
Public Overrides Sub S1(x As Integer)
End Sub
End Class
Deklarasi penimpaan dapat mengakses metode dasar yang ditimpa menggunakan akses dasar, seperti dalam contoh berikut:
Class Base
Private x As Integer
Public Overridable Sub PrintVariables()
Console.WriteLine("x = " & x)
End Sub
End Class
Class Derived
Inherits Base
Private y As Integer
Public Overrides Sub PrintVariables()
MyBase.PrintVariables()
Console.WriteLine("y = " & y)
End Sub
End Class
Dalam contoh, pemanggilan MyBase.PrintVariables() di kelas Derived memanggil metode yang PrintVariables dideklarasikan di kelas Base. Akses dasar menonaktifkan mekanisme pemanggilan yang dapat diganti dan hanya memperlakukan metode dasar sebagai metode yang tidak dapat diambil alih. Jika pemanggilan ditulis DerivedCType(Me, Base).PrintVariables(), itu akan secara rekursif memanggil metode yang PrintVariables dinyatakan dalam Derived, bukan yang dideklarasikan dalam Base.
Hanya ketika menyertakan pengubah Overrides dapat mengambil alih metode lain. Dalam semua kasus lain, metode dengan tanda tangan yang sama dengan metode yang diwariskan hanya membayangi metode yang diwariskan, seperti dalam contoh di bawah ini:
Class Base
Public Overridable Sub F()
End Sub
End Class
Class Derived
Inherits Base
Public Overridable Sub F() ' Warning, shadowing inherited F().
End Sub
End Class
Dalam contoh, metode F di kelas Derived tidak menyertakan pengubah Overrides dan oleh karena itu tidak mengambil alih metode F di kelas Base. Sebaliknya, metode F di kelas Derived membayangi metode di kelas Base, dan peringatan dilaporkan karena deklarasi tidak menyertakan Shadows atau Overloads pengubah.
Dalam contoh berikut, metode F di kelas Derived membayangi metode F yang dapat diambil alih yang diwarisi dari kelas Base:
Class Base
Public Overridable Sub F()
End Sub
End Class
Class Derived
Inherits Base
Private Shadows Sub F() ' Shadows Base.F within Derived.
End Sub
End Class
Class MoreDerived
Inherits Derived
Public Overrides Sub F() ' Ok, overrides Base.F.
End Sub
End Class
Karena metode F baru di kelas Derived memiliki Private akses, cakupannya hanya mencakup isi Derived kelas dan tidak meluas ke kelas MoreDerived. Oleh karena itu, deklarasi metode F di kelas MoreDerived diizinkan untuk mengambil alih metode F yang diwarisi dari kelas Base.
Overridable Ketika metode dipanggil, implementasi metode instans yang paling turunan dipanggil, berdasarkan jenis instans, terlepas dari apakah panggilan ke metode di kelas dasar atau kelas turunan. Implementasi metode M yang Overridable paling turunan sehubungan dengan kelas R ditentukan sebagai berikut:
Jika
Rberisi deklarasi pengenalanMOverridable, ini adalah implementasi yang paling turunan dariM.Jika tidak, jika
Rberisi penimpaan ,Mini adalah implementasi yang paling turunan dariM.Jika tidak, implementasi yang paling turunan adalah
Msama dengan kelas dasar langsung .R
Aksesibilitas
Deklarasi menentukan aksesibilitas entitas yang dinyatakannya. Aksesibilitas entitas tidak mengubah cakupan nama entitas. Domain aksesibilitas deklarasi adalah kumpulan semua ruang deklarasi tempat entitas yang dideklarasikan dapat diakses.
Lima jenis akses adalah Public, , Protected, FriendProtected Friend, dan Private.
Publicadalah jenis akses yang paling permisif, dan empat jenis lainnya adalah semua subset .Public Jenis akses yang paling tidak permisif adalah Private, dan empat jenis akses lainnya adalah semua superset dari Private.
AccessModifier
: 'Public'
| 'Protected'
| 'Friend'
| 'Private'
| 'Protected' 'Friend'
;
Jenis akses untuk deklarasi ditentukan melalui pengubah akses opsional, yang dapat berupa Public, , ProtectedFriend, Private, atau kombinasi dan ProtectedFriend. Jika tidak ada pengubah akses yang ditentukan, jenis akses default bergantung pada konteks deklarasi; jenis akses yang diizinkan juga bergantung pada konteks deklarasi.
Entitas yang dideklarasikan dengan pengubah
PublicmemilikiPublicakses. Tidak ada batasan penggunaanPublicentitas.Entitas yang dideklarasikan dengan pengubah
ProtectedmemilikiProtectedakses.Protectedakses hanya dapat ditentukan pada anggota kelas (anggota jenis reguler dan kelas berlapis) atau padaOverridableanggota modul dan struktur standar (yang harus, menurut definisi, diwarisi dariSystem.ObjectatauSystem.ValueType). AnggotaProtecteddapat diakses oleh kelas turunan, asalkan anggota bukan anggota instans, atau akses berlangsung melalui instans kelas turunan.Protectedakses bukanlah supersetFriendakses.Entitas yang dideklarasikan dengan pengubah
FriendmemilikiFriendakses. Entitas denganFriendakses hanya dapat diakses dalam program yang berisi deklarasi entitas atau rakitan apa pun yang telah diberikanFriendakses melaluiSystem.Runtime.CompilerServices.InternalsVisibleToAttributeatribut .Entitas yang dideklarasikan dengan
Protected Friendpengubah memiliki penyatuanProtecteddanFriendakses.Entitas yang dideklarasikan dengan pengubah
PrivatememilikiPrivateakses. EntitasPrivatehanya dapat diakses dalam konteks deklarasinya, termasuk entitas berlapis apa pun.
Aksesibilitas dalam deklarasi tidak bergantung pada aksesibilitas konteks deklarasi. Misalnya, jenis yang dideklarasikan dengan Private akses mungkin berisi anggota jenis dengan Public akses.
Kode berikut menunjukkan berbagai domain aksesibilitas:
Public Class A
Public Shared X As Integer
Friend Shared Y As Integer
Private Shared Z As Integer
End Class
Friend Class B
Public Shared X As Integer
Friend Shared Y As Integer
Private Shared Z As Integer
Public Class C
Public Shared X As Integer
Friend Shared Y As Integer
Private Shared Z As Integer
End Class
Private Class D
Public Shared X As Integer
Friend Shared Y As Integer
Private Shared Z As Integer
End Class
End Class
Kelas dan anggota dalam contoh ini memiliki domain aksesibilitas berikut:
Domain aksesibilitas
AdanA.Xtidak terbatas.Domain aksesibilitas dari
A.Y, ,B,B.XB.Y,B.C,B.C.X, , danB.C.Yadalah program yang berisi.Domain aksesibilitas adalah
A.ZA.Domain aksesibilitas , , , dan adalah , termasuk
B.CdanB.D.BB.D.YB.D.XB.DB.ZDomain aksesibilitas
B.C.ZadalahB.C.Domain aksesibilitas
B.D.ZadalahB.D.
Seperti yang diilustrasikan contoh, domain aksesibilitas anggota tidak pernah lebih besar dari jenis yang berisi. Misalnya, meskipun semua X anggota telah Public mendeklarasikan aksesibilitas, semua tetapi A.X memiliki domain aksesibilitas yang dibatasi oleh jenis yang berisi.
Akses ke Protected anggota instans harus melalui instans jenis turunan sehingga jenis yang tidak terkait tidak dapat memperoleh akses ke anggota yang dilindungi satu sama lain. Contohnya:
Class User
Protected Password As String
End Class
Class Employee
Inherits User
End Class
Class Guest
Inherits User
Public Function GetPassword(u As User) As String
' Error: protected access has to go through derived type.
Return U.Password
End Function
End Class
Dalam contoh di atas, kelas Guest hanya memiliki akses ke bidang yang dilindungi Password jika memenuhi syarat dengan instans .Guest Ini mencegah Guest mendapatkan akses ke Password bidang Employee objek hanya dengan mentransmisikannya ke User.
Untuk tujuan Protected akses anggota dalam jenis generik, konteks deklarasi mencakup parameter jenis. Ini berarti bahwa jenis turunan dengan satu set argumen jenis tidak memiliki akses ke Protected anggota jenis turunan dengan sekumpulan argumen jenis yang berbeda. Contohnya:
Class Base(Of T)
Protected x As T
End Class
Class Derived(Of T)
Inherits Base(Of T)
Public Sub F(y As Derived(Of String))
' Error: Derived(Of T) cannot access Derived(Of String)'s
' protected members
y.x = "a"
End Sub
End Class
Nota. Bahasa C# (dan mungkin bahasa lain) memungkinkan jenis generik untuk mengakses Protected anggota terlepas dari argumen jenis apa yang disediakan. Ini harus diingat saat merancang kelas generik yang berisi Protected anggota.
Jenis Konstituen
Jenis konstituen deklarasi adalah jenis yang direferensikan oleh deklarasi. Misalnya, jenis konstanta, jenis pengembalian metode dan jenis parameter konstruktor adalah semua jenis konstituen. Domain aksesibilitas dari jenis konstituen deklarasi harus sama dengan atau superset domain aksesibilitas deklarasi itu sendiri. Contohnya:
Public Class X
Private Class Y
End Class
' Error: Exposing private class Y outside of X.
Public Function Z() As Y
End Function
' Valid: Not exposing outside of X.
Private Function A() As Y
End Function
End Class
Friend Class B
Private Class C
End Class
' Error: Exposing private class Y outside of B.
Public Function D() As C
End Function
End Class
Nama Tipe dan Namespace Layanan
Banyak konstruksi bahasa memerlukan namespace atau jenis untuk ditentukan; ini dapat ditentukan dengan menggunakan bentuk namespace yang memenuhi syarat atau nama jenis. Nama yang memenuhi syarat terdiri dari serangkaian pengidentifikasi yang dipisahkan oleh titik; pengidentifikasi di sisi kanan periode diselesaikan dalam ruang deklarasi yang ditentukan oleh pengidentifikasi di sisi kiri periode.
Nama namespace atau jenis yang sepenuhnya memenuhi syarat adalah nama yang memenuhi syarat yang berisi nama semua yang berisi namespace dan jenis. Dengan kata lain, nama namespace layanan atau jenis yang sepenuhnya memenuhi syarat adalah N.T, di mana T adalah nama entitas dan N merupakan nama entitas yang sepenuhnya memenuhi syarat dari entitas yang berisi.
Contoh di bawah ini menunjukkan beberapa namespace layanan dan deklarasi jenis bersama dengan nama yang sepenuhnya memenuhi syarat terkait dalam komentar sebaris.
Class A ' A.
End Class
Namespace X ' X.
Class B ' X.B.
Class C ' X.B.C.
End Class
End Class
Namespace Y ' X.Y.
Class D ' X.Y.D.
End Class
End Namespace
End Namespace
Namespace X.Y ' X.Y.
Class E ' X.Y.E.
End Class
End Namespace
Amati bahwa namespace X.Y telah dideklarasikan di dua lokasi berbeda dalam kode sumber, tetapi kedua deklarasi parsial ini hanya merupakan satu namespace yang disebut X.Y yang berisi kelas D dan kelas E.
Dalam beberapa situasi, nama yang memenuhi syarat dapat dimulai dengan kata kunci Global. Kata kunci mewakili namespace terluar yang tidak disebutkan namanya, yang berguna dalam situasi di mana deklarasi membayangi namespace lampiran. Kata Global kunci memungkinkan "melarikan diri" ke namespace terluar dalam situasi itu. Contohnya:
Namespace NS1
Class System
End Class
Module Test
Sub Main()
' Error: Class System does not contain Int32
Dim x As System.Int32
' Legal, binds to System in outermost namespace
Dim y As Global.System.Int32
End Sub
End Module
End Namespace
Dalam contoh di atas, panggilan metode pertama tidak valid karena pengidentifikasi System mengikat ke kelas System, bukan namespace System. Satu-satunya System cara untuk mengakses namespace layanan adalah dengan menggunakan Global untuk keluar ke namespace layanan terluar.
Global tidak dapat digunakan dalam Imports pernyataan atau Namespace deklarasi.
Karena bahasa lain dapat memperkenalkan jenis dan namespace layanan yang cocok dengan kata kunci dalam bahasa, Visual Basic mengenali kata kunci untuk menjadi bagian dari nama yang memenuhi syarat selama mengikuti titik. Kata kunci yang digunakan dengan cara ini diperlakukan sebagai pengidentifikasi. Misalnya, pengidentifikasi X.Default.Class yang memenuhi syarat adalah pengidentifikasi yang memenuhi syarat yang valid, sementara Default.Class tidak.
Resolusi Nama yang Memenuhi Syarat untuk namespace dan jenis
Mengingat namespace layanan yang memenuhi syarat atau nama jenis formulir N.R(Of A), di mana R adalah pengidentifikasi paling kanan dalam nama yang memenuhi syarat dan A merupakan daftar argumen jenis opsional, langkah-langkah berikut menjelaskan cara menentukan namespace layanan mana atau mengetik nama yang memenuhi syarat mengacu:
Atasi
N, menggunakan aturan untuk resolusi nama yang memenuhi syarat atau tidak memenuhi syarat.Jika resolusi
Ngagal, atau diselesaikan ke parameter jenis, kesalahan waktu kompilasi terjadi.Jika tidak, jika
Rcocok dengan nama namespace layanan di N dan tidak ada argumen jenis yang disediakan, atauRcocok dengan jenis yang dapat diakses denganNjumlah parameter jenis yang sama dengan argumen jenis, jika ada, maka nama yang memenuhi syarat mengacu pada namespace atau jenis tersebut.Jika tidak, jika
Nberisi satu atau beberapa modul standar, danRcocok dengan nama jenis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam tepat satu modul standar, maka nama yang memenuhi syarat mengacu pada jenis tersebut. JikaRcocok dengan nama jenis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam lebih dari satu modul standar, kesalahan waktu kompilasi terjadi.Jika tidak, terjadi kesalahan waktu kompilasi.
Nota. Implikasi dari proses resolusi ini adalah bahwa anggota tipe tidak membayangi namespace atau jenis saat menyelesaikan namespace layanan atau nama jenis.
Resolusi Nama yang Tidak Memenuhi Syarat untuk namespace dan jenis
Mengingat nama R(Of A)yang tidak memenuhi syarat , di mana A adalah daftar argumen jenis opsional, langkah-langkah berikut menjelaskan cara menentukan namespace layanan mana atau mengetik nama yang tidak memenuhi syarat mengacu:
Jika R cocok dengan nama parameter jenis metode saat ini, dan tidak ada argumen jenis yang disediakan, maka nama yang tidak memenuhi syarat mengacu pada parameter jenis tersebut.
Untuk setiap jenis berlapis yang berisi referensi nama, mulai dari jenis terdahulu dan masuk ke terluar:
- Jika
Rcocok dengan nama parameter jenis dalam jenis saat ini dan tidak ada argumen jenis yang disediakan, maka nama yang tidak memenuhi syarat mengacu pada parameter jenis tersebut. - Jika tidak, jika
Rcocok dengan nama jenis berlapis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, maka nama yang tidak memenuhi syarat mengacu pada jenis tersebut.
- Jika
Untuk setiap namespace berlapis yang berisi referensi nama, mulai dari namespace layanan terdahulu dan masuk ke namespace layanan terluar:
- Jika
Rcocok dengan nama namespace berlapis di namespace saat ini dan tidak ada daftar argumen jenis yang disediakan, maka nama yang tidak memenuhi syarat mengacu pada namespace layanan berlapis tersebut. - Jika tidak, jika
Rcocok dengan nama jenis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, di namespace saat ini, maka nama yang tidak memenuhi syarat mengacu pada jenis tersebut. - Jika tidak, jika namespace berisi satu atau beberapa modul standar yang dapat diakses, dan
Rcocok dengan nama jenis berlapis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam satu modul standar, maka nama yang tidak memenuhi syarat mengacu pada jenis berlapis tersebut. JikaRcocok dengan nama jenis berlapis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam lebih dari satu modul standar, kesalahan waktu kompilasi terjadi.
- Jika
Jika file sumber memiliki satu atau beberapa alias impor, dan
Rcocok dengan nama salah satunya, maka nama yang tidak memenuhi syarat mengacu pada alias impor tersebut. Jika daftar argumen jenis disediakan, kesalahan waktu kompilasi terjadi.Jika file sumber yang berisi referensi nama memiliki satu atau beberapa impor:
- Jika
Rcocok dengan nama jenis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam satu impor, maka nama yang tidak memenuhi syarat mengacu pada jenis tersebut. JikaRcocok dengan nama jenis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam lebih dari satu impor dan semuanya bukan jenis yang sama, kesalahan waktu kompilasi terjadi. - Jika tidak, jika tidak ada daftar argumen jenis yang disediakan dan
Rcocok dengan nama namespace layanan dengan jenis yang dapat diakses dalam satu impor, maka nama yang tidak memenuhi syarat mengacu pada namespace tersebut. Jika tidak ada daftar argumen tipe yang disediakan danRcocok dengan nama namespace layanan dengan jenis yang dapat diakses dalam lebih dari satu impor dan semua bukan namespace layanan yang sama, kesalahan waktu kompilasi terjadi. - Jika tidak, jika impor berisi satu atau beberapa modul standar yang dapat diakses, dan
Rcocok dengan nama jenis berlapis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam satu modul standar, maka nama yang tidak memenuhi syarat mengacu pada jenis tersebut. JikaRcocok dengan nama jenis berlapis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam lebih dari satu modul standar, kesalahan waktu kompilasi terjadi.
- Jika
Jika lingkungan kompilasi mendefinisikan satu atau beberapa alias impor, dan
Rcocok dengan nama salah satunya, maka nama yang tidak memenuhi syarat mengacu pada alias impor tersebut. Jika daftar argumen jenis disediakan, kesalahan waktu kompilasi terjadi.Jika lingkungan kompilasi mendefinisikan satu atau beberapa impor:
- Jika
Rcocok dengan nama jenis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam satu impor, maka nama yang tidak memenuhi syarat mengacu pada jenis tersebut. JikaRcocok dengan nama jenis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam lebih dari satu impor, kesalahan waktu kompilasi terjadi. - Jika tidak, jika tidak ada daftar argumen jenis yang disediakan dan
Rcocok dengan nama namespace layanan dengan jenis yang dapat diakses dalam satu impor, maka nama yang tidak memenuhi syarat mengacu pada namespace tersebut. Jika tidak ada daftar argumen jenis yang disediakan danRcocok dengan nama namespace layanan dengan jenis yang dapat diakses dalam lebih dari satu impor, kesalahan waktu kompilasi terjadi. - Jika tidak, jika impor berisi satu atau beberapa modul standar yang dapat diakses, dan
Rcocok dengan nama jenis berlapis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam satu modul standar, maka nama yang tidak memenuhi syarat mengacu pada jenis tersebut. JikaRcocok dengan nama jenis berlapis yang dapat diakses dengan jumlah parameter jenis yang sama dengan argumen jenis, jika ada, dalam lebih dari satu modul standar, kesalahan waktu kompilasi terjadi.
- Jika
Jika tidak, terjadi kesalahan waktu kompilasi.
Nota. Implikasi dari proses resolusi ini adalah bahwa anggota tipe tidak membayangi namespace atau jenis saat menyelesaikan namespace layanan atau nama jenis.
Biasanya, nama hanya dapat terjadi sekali di namespace tertentu. Namun, karena namespace dapat dideklarasikan di beberapa rakitan .NET, dimungkinkan untuk memiliki situasi di mana dua rakitan menentukan jenis dengan nama yang sepenuhnya memenuhi syarat yang sama. Dalam hal ini, jenis yang dideklarasikan dalam kumpulan file sumber saat ini lebih disukai daripada jenis yang dideklarasikan dalam rakitan .NET eksternal. Jika tidak, namanya ambigu dan tidak ada cara untuk membedakan nama.
Variabel
Variabel mewakili lokasi penyimpanan. Setiap variabel memiliki jenis yang menentukan nilai apa yang dapat disimpan dalam variabel. Karena Visual Basic adalah bahasa yang aman jenis, setiap variabel dalam program memiliki jenis dan bahasa menjamin bahwa nilai yang disimpan dalam variabel selalu dari jenis yang sesuai. Variabel selalu diinisialisasi ke nilai default jenisnya sebelum referensi apa pun ke variabel dapat dibuat. Tidak dimungkinkan untuk mengakses memori yang tidak diinisialisasi.
Jenis dan Metode Generik
Jenis (kecuali untuk modul standar dan jenis enumerasi) dan metode dapat mendeklarasikan parameter jenis, yang merupakan jenis yang tidak akan disediakan sampai instans jenis dideklarasikan atau metode dipanggil. Jenis dan metode dengan parameter jenis juga dikenal sebagai jenis generik dan metode generik, masing-masing, karena jenis atau metode harus ditulis secara generik, tanpa pengetahuan khusus tentang jenis yang akan disediakan oleh kode yang menggunakan jenis atau metode.
Nota. Saat ini, meskipun metode dan delegasi dapat bersifat generik, properti, peristiwa, dan operator tidak dapat dibuat sendiri. Namun, mereka dapat menggunakan parameter jenis dari kelas yang berisi.
Dari perspektif jenis atau metode generik, parameter jenis adalah jenis tempat penampung yang akan diisi dengan jenis aktual ketika jenis atau metode digunakan. Argumen jenis digantikan untuk parameter jenis dalam jenis atau metode pada titik di mana jenis atau metode digunakan. Misalnya, kelas tumpukan generik dapat diimplementasikan sebagai:
Public Class Stack(Of ItemType)
Protected Items(0 To 99) As ItemType
Protected CurrentIndex As Integer = 0
Public Sub Push(data As ItemType)
If CurrentIndex = 100 Then
Throw New ArgumentException("Stack is full.")
End If
Items(CurrentIndex) = Data
CurrentIndex += 1
End Sub
Public Function Pop() As ItemType
If CurrentIndex = 0 Then
Throw New ArgumentException("Stack is empty.")
End If
CurrentIndex -= 1
Return Items(CurrentIndex + 1)
End Function
End Class
Deklarasi yang menggunakan Stack(Of ItemType) kelas harus menyediakan argumen jenis untuk parameter ItemTypejenis . Jenis ini kemudian diisi di mana pun ItemType digunakan dalam kelas:
Option Strict On
Module Test
Sub Main()
Dim s1 As New Stack(Of Integer)()
Dim s2 As New Stack(Of Double)()
s1.Push(10.10) ' Error: Stack(Of Integer).Push takes an Integer
s2.Push(10.10) ' OK: Stack(Of Double).Push takes a Double
Console.WriteLine(s2.Pop().GetType().ToString()) ' Prints: Double
End Sub
End Module
Parameter Jenis
Parameter jenis dapat disediakan pada deklarasi jenis atau metode. Setiap parameter jenis adalah pengidentifikasi yang merupakan place-holder untuk argumen jenis yang disediakan untuk membuat jenis atau metode yang dibangun. Sebaliknya, argumen jenis adalah jenis aktual yang digantikan untuk parameter jenis saat jenis atau metode generik digunakan.
TypeParameterList
: OpenParenthesis 'Of' TypeParameter ( Comma TypeParameter )* CloseParenthesis
;
TypeParameter
: VarianceModifier? Identifier TypeParameterConstraints?
;
VarianceModifier
: 'In' | 'Out'
;
Setiap parameter jenis dalam deklarasi jenis atau metode mendefinisikan nama dalam ruang deklarasi jenis atau metode tersebut. Dengan demikian, parameter tidak dapat memiliki nama yang sama dengan parameter jenis lain, anggota jenis, parameter metode, atau variabel lokal. Cakupan parameter jenis pada jenis atau metode adalah seluruh jenis atau metode. Karena parameter jenis dilingkup ke seluruh deklarasi jenis, jenis berlapis dapat menggunakan parameter jenis luar. Ini juga berarti bahwa parameter jenis harus selalu ditentukan saat mengakses jenis yang berlapis di dalam jenis generik:
Public Class Outer(Of T)
Public Class Inner
Public Sub F(x As T)
...
End Sub
End Class
End Class
Module Test
Sub Main()
Dim x As New Outer(Of Integer).Inner()
...
End Sub
End Module
Tidak seperti anggota kelas lainnya, parameter jenis tidak diwariskan. Parameter jenis dalam jenis hanya dapat dirujuk dengan nama sederhananya; dengan kata lain, nama tersebut tidak dapat memenuhi syarat dengan nama jenis yang berisi. Meskipun gaya pemrogramannya buruk, parameter jenis dalam jenis berlapis dapat menyembunyikan parameter anggota atau jenis yang dideklarasikan dalam jenis luar:
Class Outer(Of T)
Class Inner(Of T)
Public t1 As T ' Refers to Inner's T
End Class
End Class
Jenis dan metode dapat kelebihan beban berdasarkan jumlah parameter jenis (atau aritas) yang dinyatakan jenis atau metode. Misalnya, deklarasi berikut adalah legal:
Module C
Sub M()
End Sub
Sub M(Of T)()
End Sub
Sub M(Of T, U)()
End Sub
End Module
Structure C(Of T)
Dim x As T
End Structure
Class C(Of T, U)
End Class
Dalam kasus jenis, kelebihan beban selalu dicocokkan dengan jumlah argumen jenis yang ditentukan. Ini berguna saat menggunakan kelas generik dan non-generik bersama-sama dalam program yang sama:
Class Queue
End Class
Class Queue(Of T)
End Class
Class X
Dim q1 As Queue ' Non-generic queue
Dim q2 As Queue(Of Integer) ' Generic queue
End Class
Aturan untuk metode yang kelebihan beban pada parameter jenis tercakup dalam bagian tentang resolusi kelebihan beban metode.
Dalam deklarasi yang berisi, parameter jenis dianggap sebagai jenis lengkap. Karena parameter jenis dapat dibuat dengan banyak argumen jenis aktual yang berbeda, parameter jenis memiliki operasi dan pembatasan yang sedikit berbeda dari jenis lain seperti yang dijelaskan di bawah ini:
Parameter jenis tidak dapat digunakan secara langsung untuk mendeklarasikan kelas atau antarmuka dasar.
Aturan untuk pencarian anggota pada parameter jenis bergantung pada batasan, jika ada, diterapkan ke parameter jenis.
Konversi yang tersedia untuk parameter jenis bergantung pada batasan, jika ada, diterapkan ke parameter jenis.
Dengan tidak adanya batasan
Structure, nilai dengan jenis yang diwakili oleh parameter jenis dapat dibandingkan denganNothingmenggunakanIsdanIsNot.Parameter jenis hanya dapat digunakan dalam
Newekspresi jika parameter jenis dibatasi olehNewbatasan atauStructure.Parameter jenis tidak dapat digunakan di mana saja dalam pengecualian atribut dalam
GetTypeekspresi.Parameter jenis dapat digunakan sebagai argumen jenis ke jenis dan parameter generik lainnya.
Contoh berikut adalah jenis generik yang memperluas Stack(Of ItemType) kelas:
Class MyStack(Of ItemType)
Inherits Stack(Of ItemType)
Public ReadOnly Property Size() As Integer
Get
Return CurrentIndex
End Get
End Property
End Class
Ketika deklarasi memasok argumen jenis ke MyStack, argumen jenis yang sama juga akan diterapkan Stack .
Sebagai jenis, parameter jenis murni konstruksi waktu kompilasi. Pada run-time, setiap parameter jenis terikat ke jenis run-time yang ditentukan dengan menyediakan argumen jenis ke deklarasi generik. Dengan demikian, jenis variabel yang dideklarasikan dengan parameter jenis akan, pada run-time, menjadi jenis non-generik atau jenis tertentu yang dibangun. Eksekusi run-time dari semua pernyataan dan ekspresi yang melibatkan parameter jenis menggunakan jenis aktual yang disediakan sebagai argumen jenis untuk parameter tersebut.
Batasan Jenis
Karena argumen jenis dapat berupa jenis apa pun dalam sistem jenis, jenis atau metode generik tidak dapat membuat asumsi apa pun tentang parameter jenis. Dengan demikian, anggota parameter jenis dianggap sebagai anggota jenis Object, karena semua jenis berasal dari Object.
Dalam kasus koleksi seperti Stack(Of ItemType), fakta ini mungkin bukan batasan yang sangat penting, tetapi mungkin ada kasus di mana jenis generik mungkin ingin membuat asumsi tentang jenis yang akan disediakan sebagai argumen jenis.
Batasan jenis dapat ditempatkan pada parameter jenis yang membatasi jenis mana yang dapat disediakan sebagai parameter jenis dan memungkinkan jenis atau metode generik untuk mengasumsikan lebih banyak tentang parameter jenis.
TypeParameterConstraints
: 'As' Constraint
| 'As' OpenCurlyBrace ConstraintList CloseCurlyBrace
;
ConstraintList
: Constraint ( Comma Constraint )*
;
Constraint
: TypeName
| 'New'
| 'Structure'
| 'Class'
;
Public Class DisposableStack(Of ItemType As IDisposable)
Implements IDisposable
Private _items(0 To 99) As ItemType
Private _currentIndex As Integer = 0
Public Sub Push(data As ItemType)
...
End Sub
Public Function Pop() As ItemType
...
End Function
Private Sub Dispose() Implements IDisposable.Dispose
For Each item As IDisposable In _items
If item IsNot Nothing Then
item.Dispose()
End If
Next item
End Sub
End Class
Dalam contoh ini, DisposableStack(Of ItemType) membatasi parameter jenisnya hanya untuk jenis yang mengimplementasikan antarmuka System.IDisposable. Akibatnya, ia dapat menerapkan Dispose metode yang membuang objek apa pun yang masih tersisa dalam antrean.
Batasan jenis harus merupakan salah satu batasan Classkhusus , , Structureatau New, atau , atau harus merupakan jenis T di mana:
Tadalah kelas, antarmuka, atau parameter jenis.TbukanNotInheritable.Tbukan salah satu dari, atau jenis yang diwarisi dari salah satu, jenis khusus berikut:System.Array, ,System.Delegate,System.MulticastDelegateSystem.Enum, atauSystem.ValueType.TbukanObject. Karena semua jenis berasal dariObject, batasan seperti itu tidak akan berpengaruh jika diizinkan.Tsetidaknya harus dapat diakses sebagai jenis atau metode generik yang dinyatakan.
Batasan beberapa jenis dapat ditentukan untuk parameter jenis tunggal dengan mengapit batasan jenis dalam kurung kurawal ({}).. Hanya satu batasan jenis untuk parameter jenis tertentu yang dapat menjadi kelas. Ini adalah kesalahan untuk menggabungkan Structure batasan khusus dengan batasan kelas bernama atau batasan Class khusus.
Class ControlFactory(Of T As {Control, New})
...
End Class
Batasan jenis dapat menggunakan jenis yang berisi atau salah satu parameter jenis yang berisi. Dalam contoh berikut, batasan mengharuskan argumen jenis yang disediakan mengimplementasikan antarmuka generik menggunakan dirinya sendiri sebagai argumen jenis:
Class Sorter(Of V As IComparable(Of V))
...
End Class
Batasan Class jenis khusus membatasi argumen jenis yang disediakan ke jenis referensi apa pun.
Nota. Batasan Class jenis khusus dapat dipenuhi oleh antarmuka. Dan struktur dapat mengimplementasikan antarmuka. Oleh karena itu, batasan (Of T As U, U As Class) mungkin terpenuhi dengan "T" struktur (yang tidak memenuhi Class batasan khusus), dan "U" antarmuka yang diterapkannya (yang memenuhi Class batasan khusus).
Batasan Structure jenis khusus membatasi argumen jenis yang disediakan ke jenis nilai apa pun kecuali System.Nullable(Of T).
Nota. Batasan struktur tidak memungkinkan System.Nullable(Of T) sehingga tidak dimungkinkan untuk menyediakan System.Nullable(Of T) sebagai argumen jenis untuk dirinya sendiri.
Batasan New jenis khusus mengharuskan argumen jenis yang disediakan harus memiliki konstruktor tanpa parameter yang dapat diakses dan tidak dapat dinyatakan MustInherit. Contohnya:
Class Factory(Of T As New)
Function CreateInstance() As T
Return New T()
End Function
End Class
Batasan jenis kelas mengharuskan argumen jenis yang disediakan haruslah jenis tersebut sebagai atau mewarisinya. Batasan jenis antarmuka mengharuskan argumen jenis yang disediakan harus mengimplementasikan antarmuka tersebut. Batasan parameter jenis mengharuskan argumen jenis yang disediakan harus berasal dari atau menerapkan semua batas yang diberikan untuk parameter jenis yang cocok. Contohnya:
Class List(Of T)
Sub AddRange(Of S As T)(collection As IEnumerable(Of S))
...
End Sub
End Class
Dalam contoh ini, parameter S jenis aktif dibatasi AddRange ke parameter TListjenis . Ini berarti bahwa List(Of Control) akan membatasi AddRangeparameter jenis ke jenis apa pun yang atau mewarisi dari Control.
Batasan Of S As T parameter jenis diselesaikan dengan menambahkan semua batasan Tsecara transitif ke S, selain batasan khusus (Class, , StructureNew). Ini adalah kesalahan untuk memiliki batasan melingkar (misalnya Of S As T, T As S). Ini adalah kesalahan untuk memiliki batasan parameter jenis yang memiliki batasan Structure . Setelah menambahkan batasan, ada kemungkinan bahwa sejumlah situasi khusus dapat terjadi:
Jika ada beberapa batasan kelas, kelas yang paling turunan dianggap sebagai batasan. Jika satu atau beberapa batasan kelas tidak memiliki hubungan warisan, batasan tidak dapat dipenuhi dan itu adalah kesalahan.
Jika parameter jenis menggabungkan
Structurebatasan khusus dengan batasan kelas bernama atauClassbatasan khusus, itu adalah kesalahan. Batasan kelas mungkinNotInheritable, dalam hal ini tidak ada jenis turunan dari batasan tersebut yang diterima dan itu adalah kesalahan.
Jenisnya mungkin salah satu dari, atau jenis yang diwarisi dari, jenis khusus berikut: System.Array, , System.Delegate, System.MulticastDelegateSystem.Enum, atau System.ValueType. Dalam hal ini, hanya jenis, atau jenis yang diwarisi darinya, yang diterima. Parameter jenis yang dibatasi ke salah satu jenis ini hanya dapat menggunakan konversi yang diizinkan oleh DirectCast operator. Contohnya:
MustInherit Class Base(Of T)
MustOverride Sub S1(Of U As T)(x As U)
End Class
Class Derived
Inherits Base(Of Integer)
' The constraint of U must be Integer, which is normally not allowed.
Overrides Sub S1(Of U As Integer)(x As U)
Dim y As Integer = x ' OK
Dim z As Long = x ' Error: Can't convert
End Sub
End Class
Selain itu, parameter jenis yang dibatasi untuk jenis nilai karena salah satu relaksasi di atas tidak dapat memanggil metode apa pun yang ditentukan pada jenis nilai tersebut. Contohnya:
Class C1(Of T)
Overridable Sub F(Of G As T)(x As G)
End Sub
End Class
Class C2
Inherits C1(Of IntPtr)
Overrides Sub F(Of G As IntPtr)(ByVal x As G)
' Error: Cannot access structure members
x.ToInt32()
End Sub
End Class
Jika batasan, setelah substitusi, berakhir sebagai jenis array, jenis array kovarian apa pun juga diizinkan. Contohnya:
Module Test
Class B
End Class
Class D
Inherits B
End Class
Function F(Of T, U As T)(x As U) As T
Return x
End Function
Sub Main()
Dim a(9) As B
Dim b(9) As D
a = F(Of B(), D())(b)
End Sub
End Module
Parameter jenis dengan batasan kelas atau antarmuka dianggap memiliki anggota yang sama dengan batasan kelas atau antarmuka tersebut. Jika parameter jenis memiliki beberapa batasan, parameter jenis dianggap memiliki persatuan semua anggota batasan. Jika ada anggota dengan nama yang sama dalam lebih dari satu batasan, maka anggota disembunyikan dalam urutan berikut: batasan kelas menyembunyikan anggota dalam batasan antarmuka, yang menyembunyikan anggota di System.ValueType (jika Structure batasan ditentukan), yang menyembunyikan anggota di Object. Jika anggota dengan nama yang sama muncul di lebih dari satu batasan antarmuka, anggota tidak tersedia (seperti dalam beberapa pewarisan antarmuka) dan parameter jenis harus ditransmisikan ke antarmuka yang diinginkan. Contohnya:
Class C1
Sub S1(x As Integer)
End Sub
End Class
Interface I1
Sub S1(x As Integer)
End Interface
Interface I2
Sub S1(y As Double)
End Interface
Module Test
Sub T1(Of T As {C1, I1, I2})()
Dim a As T
a.S1(10) ' Calls C1.S1, which is preferred
a.S1(10.10) ' Also calls C1.S1, class is still preferred
End Sub
Sub T2(Of T As {I1, I2})()
Dim a As T
a.S1(10) ' Error: Call is ambiguous between I1.S1, I2.S1
End Sub
End Module
Saat menyediakan parameter jenis sebagai argumen jenis, parameter jenis harus memenuhi batasan parameter jenis yang cocok.
Class Base(Of T As Class)
End Class
Class Derived(Of V)
' Error: V does not satisfy the constraints of T
Inherits Base(Of V)
End Class
Nilai parameter jenis yang dibatasi dapat digunakan untuk mengakses anggota instans, termasuk metode instans, yang ditentukan dalam batasan.
Interface IPrintable
Sub Print()
End Interface
Class Printer(Of V As IPrintable)
Sub PrintOne(v1 As V)
V1.Print()
End Sub
End Class
Jenis Varians Parameter
Parameter jenis dalam antarmuka atau deklarasi jenis delegasi dapat secara opsional menentukan pengubah varians. Ketik parameter dengan pengubah varian membatasi bagaimana parameter jenis dapat digunakan dalam jenis antarmuka atau delegasi tetapi memungkinkan antarmuka generik atau jenis delegasi untuk dikonversi ke jenis generik lain dengan argumen jenis yang kompatibel dengan varian. Contohnya:
Class Base
End Class
Class Derived
Inherits Base
End Class
Module Test
Sub Main()
Dim x As IEnumerable(Of Derived) = ...
' OK, as IEnumerable(Of Base) is variant compatible
' with IEnumerable(Of Derived)
Dim y As IEnumerable(Of Base) = x
End Sub
End Module
Antarmuka generik yang memiliki parameter jenis dengan pengubah varians memiliki beberapa batasan:
Mereka tidak dapat berisi deklarasi peristiwa yang menentukan daftar parameter (tetapi deklarasi peristiwa kustom atau deklarasi peristiwa dengan jenis delegasi diizinkan).
Mereka tidak boleh berisi kelas berlapis, struktur, atau jenis enumerasi.
Nota. Pembatasan ini disebabkan oleh fakta bahwa jenis yang disarangkan dalam jenis generik secara implisit menyalin parameter generik induknya. Dalam kasus kelas berlapis, struktur, atau jenis enumerasi, jenis jenis tersebut tidak dapat memiliki pengubah varians pada parameter jenisnya. Dalam kasus deklarasi peristiwa dengan daftar parameter, kelas delegasi berlapis yang dihasilkan dapat memiliki kesalahan yang membingungkan ketika jenis yang tampaknya digunakan dalam In posisi (yaitu jenis parameter) sebenarnya digunakan dalam Out posisi (yaitu jenis peristiwa).
Parameter jenis yang dideklarasikan dengan pengubah Keluar kovarian. Secara informal, parameter jenis kovarian hanya dapat digunakan dalam posisi output -- yaitu nilai yang dikembalikan dari antarmuka atau jenis delegasi -- dan tidak dapat digunakan dalam posisi input. Jenis T dianggap valid secara kovarian jika:
Tadalah jenis kelas, struktur, atau enumerasi.Tadalah delegasi non-generik atau jenis antarmuka.Tadalah jenis array yang jenis elemennya valid secara kovarian.Tadalah parameter jenis yang tidak dideklarasikan sebagaiOutparameter jenis.Tadalah antarmuka yang dibangun atau jenisX(Of P1,...,Pn)delegasi dengan argumenA1,...,Anjenis sedih sehingga:Jika
Pidinyatakan sebagai parameter Jenis keluar, makaAiberlaku secara kovarian.Jika
Pidinyatakan sebagai parameter Jenis dalam, makaAivalid secara kontravarian.
Berikut ini harus valid secara kovarian dalam antarmuka atau jenis delegasi:
Antarmuka dasar antarmuka.
Jenis pengembalian fungsi atau jenis delegasi.
Jenis properti jika ada
Getaksesor.Jenis parameter apa pun
ByRef.
Contohnya:
Delegate Function D(Of Out T, U)(x As U) As T
Interface I1(Of Out T)
End Interface
Interface I2(Of Out T)
Inherits I1(Of T)
' OK, T is only used in an Out position
Function M1(x As I1(Of T)) As T
' Error: T is used in an In position
Function M2(x As T) As T
End Interface
Nota.
Out bukan kata yang dipesan.
Parameter jenis yang dideklarasikan dengan pengubah Dalam kontravarian. Secara informal, parameter jenis kontravarian hanya dapat digunakan dalam posisi input -- yaitu nilai yang sedang diteruskan ke antarmuka atau jenis delegasi -- dan tidak dapat digunakan dalam posisi output. Jenis T dianggap valid secara kontravarian jika:
Tadalah jenis kelas, struktur, atau enumerasi.Tadalah delegasi non-generik atau jenis antarmuka.Tadalah jenis array yang jenis elemennya valid secara kontravarian.Tadalah parameter jenis yang tidak dideklarasikan sebagai parameter Jenis dalam.Tadalah antarmuka yang dibangun atau jenisX(Of P1,...,Pn)delegasi dengan argumenA1,...,Anjenis sedih sehingga:Jika
Pidinyatakan sebagaiOutparameter jenis, makaAivalid secara kontravarian.Jika
Pidinyatakan sebagaiInparameter jenis, makaAivalid secara kovarian.
Berikut ini harus valid secara kontravarian dalam antarmuka atau jenis delegasi:
Jenis parameter.
Batasan jenis pada parameter jenis metode.
Jenis properti jika memiliki
Setaksesor.Jenis peristiwa.
Contohnya:
Delegate Function D(Of T, In U)(x As U) As T
Interface I1(Of In T)
End Interface
Interface I2(Of In T)
' OK, T is only used in an In position
Sub M1(x As I1(Of T))
' Error: T is used in an Out position
Function M2() As T
End Interface
Dalam kasus di mana jenis harus valid secara kontravarian dan kovarians (seperti properti dengan Get pengakses dan Set atau ByRef parameter), parameter jenis varian tidak dapat digunakan.
Variansi bersama dan kontra menimbulkan "masalah ambiguitas berlian". Pertimbangkan kode berikut:
Class C
Implements IEnumerable(Of String)
Implements IEnumerable(Of Exception)
Public Function GetEnumerator1() As IEnumerator(Of String) _
Implements IEnumerable(Of String).GetEnumerator
Console.WriteLine("string")
End Function
Public Function GetEnumerator2() As IEnumerator(Of Exception) _
Implements IEnumerable(Of Execption).GetEnumerator
Console.WriteLine("exception")
End Function
End Class
Dim c As IEnumerable(Of Object) = New C
c.GetEnumerator()
C Kelas dapat dikonversi menjadi IEnumerable(Of Object) dengan dua cara, baik melalui konversi kovarian dari IEnumerable(Of String) dan melalui konversi kovarian dari IEnumerable(Of Exception). CLR tidak menentukan mana dari dua metode yang akan dipanggil oleh c.GetEnumerator(). Secara umum, setiap kali kelas dinyatakan untuk mengimplementasikan antarmuka kovarian dengan dua argumen generik berbeda yang memiliki supertipe umum (misalnya dalam hal String ini dan Exception memiliki supertipe Objectumum ), atau kelas dinyatakan untuk mengimplementasikan antarmuka kontravarian dengan dua argumen generik berbeda yang memiliki subjenis umum, maka ambiguitas kemungkinan muncul. Kompilator memberikan peringatan pada deklarasi tersebut.
Visual Basic language spec