Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a fejezet a Microsoft Visual Basic nyelv szemantikájának megértéséhez szükséges fogalmakat ismerteti. Sok fogalomnak ismernie kell a Visual Basic programozókat vagy a C/C++ programozókat, de pontos definícióik eltérhetnek.
Nyilatkozatok
A Visual Basic program nevesített entitásokból áll. Ezek az entitások deklarációkon keresztül kerülnek bevezetésre, és a program "jelentését" képviselik.
Felső szinten a névterek olyan entitások , amelyek más entitásokat, például beágyazott névtereket és típusokat rendszereznek. A típusok olyan entitások, amelyek értékeket írnak le, és végrehajtható kódot definiálnak. A típusok beágyazott típusokat és típustagokat tartalmazhatnak. A típustagok állandók, változók, metódusok, operátorok, tulajdonságok, események, számbavételi értékek és konstruktorok.
A más entitásokat tartalmazó entitások deklarációs területet határoznak meg. Az entitások deklarációs területre deklarációval vagy örökléssel kerülnek be; a tároló deklarációs területet az entitások deklarációs környezetének nevezzük. Ha egy entitást deklarál egy deklarációs térben, egy új deklarációs területet határoz meg, amely további beágyazott entitásdeklarációkat tartalmazhat; így a program deklarációi a deklarációs szóközök hierarchiáját alkotják.
A túlterhelt típusú tagok kivételével érvénytelen, ha a deklarációk azonos nevű entitásokat vezetnek be ugyanabba a deklarációs környezetbe. Ezenkívül a deklarációs tér soha nem tartalmazhat azonos nevű különböző típusú entitásokat; Egy deklarációs tér például soha nem tartalmazhat változót és metódust ugyanazzal a névvel.
Jegyzet. Más nyelveken is létrehozhat olyan deklarációs területet, amely különböző típusú, azonos nevű entitásokat tartalmaz (például ha a nyelv megkülönbözteti a kis- és nagybetűket, és különböző deklarációkat engedélyez a burkolat alapján). Ebben az esetben a leginkább elérhető entitást ehhez a névhez kötve tekintik; ha egynél több entitástípus érhető el a leginkább, akkor a név nem egyértelmű.
Public akadálymentesebb, mint Protected Frienda , Protected FriendProtectedFriendvagy , és ProtectedFriend akadálymentesebb, mint Privatea .
A névtér deklarációs területe "nyitott végű", így két azonos teljes névvel rendelkező névtér-deklaráció is hozzájárul ugyanahhoz a deklarációs térhez. Az alábbi példában a két névtér-deklaráció ugyanahhoz a deklarációs térhez járul hozzá, ebben az esetben két osztályt deklarál a teljes névvel Data.Customer és Data.Order:
Namespace Data
Class Customer
End Class
End Namespace
Namespace Data
Class Order
End Class
End Namespace
Mivel a két deklaráció ugyanahhoz a deklarációs térhez járul hozzá, fordítási időhiba lépne fel, ha mindegyik egy azonos nevű osztály deklarációját tartalmazná.
Túlterhelés és aláírások
A deklarációs térben azonos nevű entitások deklarálásának egyetlen módja a túlterhelés. Csak a metódusok, operátorok, példánykonstruktorok és tulajdonságok terhelhetők túl.
A túlterhelt típustagoknak egyedi aláírásokkal kell rendelkezniük. A típustagok aláírása a típusparaméterek számából, valamint a tag paramétereinek számából és típusaiból áll. A konverziós operátorok az operátor visszatérési típusát is tartalmazzák az aláírásban.
Az alábbiak nem részei a tagok aláírásának, ezért nem terhelhetők túl:
Módosítja egy típustagot (például
SharedvagyPrivate).Módosítók egy paraméterre (például
ByValByRef).A paraméterek neve.
Egy metódus vagy operátor visszatérési típusa (a konverziós operátorok kivételével) vagy egy tulajdonság elemtípusa.
Típusparaméter korlátozásai.
Az alábbi példa a túlterhelt metódusok deklarációit és aláírásait mutatja be. Ez a deklaráció nem lenne érvényes, mivel számos módszerdeklaráció azonos aláírásokkal rendelkezik.
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
Érvényes olyan általános típust definiálni, amely a megadott típusargumentumok alapján azonos aláírással rendelkező tagokat tartalmazhat. A túlterhelés feloldására vonatkozó szabályokat használjuk az ilyen túlterhelések közötti egyértelműsítésre, bár lehetnek olyan helyzetek, amelyekben lehetetlen egyértelműsíteni. Például:
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
Hatókör
Az entitás nevének hatóköre az összes olyan deklarációs szóköz halmaza, amelyen belül a névre minősítés nélkül is hivatkozhat. Az entitás nevének hatóköre általában a teljes deklarációs környezet; az entitás deklarációja azonban tartalmazhat azonos nevű entitások beágyazott deklarációit. Ebben az esetben a beágyazott entitás árnyékolása vagy elrejtése a külső entitás, és az árnyékolt entitáshoz való hozzáférés csak minősítéssel lehetséges.
A beágyazáson keresztüli árnyékolás névterekben vagy névterekbe ágyazott típusokban, más típusokba ágyazott típusokban és a típustagok testében történik. A deklarációk beágyazása mindig implicit módon történik; nincs szükség explicit szintaxisra.
Az alábbi példában a metóduson belül a F példányváltozót i a helyi változó iárnyékozza, i de a G metóduson belül továbbra is a példányváltozóra hivatkozik.
Class Test
Private i As Integer = 0
Sub F()
Dim i As Integer = 1
End Sub
Sub G()
i = 1
End Sub
End Class
Ha egy belső hatókörben lévő név elrejt egy nevet egy külső hatókörben, az árnyékot ad a név túlterhelt előfordulásának. Az alábbi példában Inner a hívás F(1) meghívja a F deklaráltat, mert a belső deklaráció minden külső előfordulását F elrejti. Ugyanebből az okból a hívás F("Hello") hibás.
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
Örökség
Az öröklési kapcsolat az, amelyben az egyik típus (a származtatott típus) egy másikból ( az alaptípusból ) származik, így a származtatott típus deklarációs területe implicit módon tartalmazza az akadálymentes nem konstruktor típusú tagokat és az alaptípus beágyazott típusait. Az alábbi példában az osztály A a ( ) alaposztálya B, és B abból Aszármazik.
Class A
End Class
Class B
Inherits A
End Class
Mivel A nem határoz meg explicit módon alaposztályt, az alaposztály implicit módon Objectvan megadva.
Az öröklés fontos szempontjai a következők:
Az öröklés tranzitív. Ha a C típus B típusból származik, és a B típus az A típusból származik, a C típus örökli a B típusban deklarált típustagokat, valamint az A típusban deklarált típustagokat.
A származtatott típus kiterjed, de nem szűkíthető, alaptípusa. A származtatott típus új típustagokat adhat hozzá, és árnyékolhatja az örökölt típustagokat, de nem távolíthatja el az örökölt típustagok definícióját.
Mivel egy típuspéldány az alaptípus összes típustagját tartalmazza, a konvertálás mindig létezik származtatott típusból az alaptípusba.
A típus
Objectkivételével minden típusnak alaptípussal kell rendelkeznie.ObjectÍgy az összes típus végső alaptípusa, és minden típus átalakítható rá.A származtatás körkörössége nem engedélyezett. Vagyis ha egy típus
Begy típusbólAszármazik , akkor a típusAközvetlenül vagy közvetve származik a típusbólB.Egy típus nem származhat közvetlenül vagy közvetve a benne beágyazott típusból.
Az alábbi példa fordítási időt eredményez, mert az osztályok körkörösen függenek egymástól.
Class A
Inherits B
End Class
Class B
Inherits C
End Class
Class C
Inherits A
End Class
Az alábbi példa fordítási időt is eredményez, mert B közvetetten a beágyazott osztályból C származik az osztályon Akeresztül.
Class A
Inherits B.C
End Class
Class B
Inherits A
Public Class C
End Class
End Class
A következő példa nem eredményez hibát, mert az osztály A nem az osztályból Bszármazik.
Class A
Class B
Inherits A
End Class
End Class
MustInherit és NotInheritable osztályok
Az MustInherit osztály olyan hiányos típus, amely csak alaptípusként működhet. Az MustInherit osztályokat nem lehet példányosítva létrehozni, ezért hiba az New operátort használni. Az osztályok változóinak MustInherit deklarálása érvényes; ezek a változók csak az osztályból származtatott osztályhoz rendelhetők hozzá Nothing , vagy egy olyan értékhez, amely az MustInherit osztályból származik.
Ha egy normál osztály egy MustInherit osztályból származik, a normál osztálynak felül kell bírálnia az összes örökölt tagot MustOverride . Például:
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
Az MustInherit osztály A bevezet egy metódustFMustOverride. Az osztály B egy további módszert Gvezet be, de nem nyújt implementációt .F Ezért az osztályt B is deklarálni MustInheritkell . Osztály C felülbírálások F , és tényleges megvalósítást biztosít. Mivel nincsenek kiemelkedő MustOverride tagok az osztályban C, nem szükséges MustInherit.
Az NotInheritable osztály olyan osztály, amelyből egy másik osztály nem származtatható.
NotInheritable osztályokat elsősorban a nem szándékos származtatás megelőzésére használnak.
Ebben a példában az osztály B hibás, mert az osztályból NotInheritableApróbál származni. Az osztály nem jelölhető meg egyszerre MustInherit és NotInheritable.
NotInheritable Class A
End Class
Class B
' Error, a class cannot derive from a NotInheritable class.
Inherits A
End Class
Interfészek és többszörös öröklés
Más típusokkal ellentétben, amelyek csak egy alaptípusból származnak, az illesztő több alapillesztőből is származhat. Emiatt az illesztő egy azonos nevű típustagot örökölhet különböző alapillesztőktől. Ilyen esetben a szorzott öröklődő név nem érhető el a származtatott felületen, és ha a származtatott felületen keresztül hivatkozik ezekre a típustagokra, fordítási időt érintő hibát okoz, az aláírásoktól és a túlterheléstől függetlenül. Ehelyett az ütköző típusú tagokra alapfelület-névvel kell hivatkozni.
Az alábbi példában az első két utasítás fordítási időt eredményez, mert a szorzott tag Count nem érhető el a felületen 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
Ahogy a példában látható, a kétértelműséget az x megfelelő alapinterfész típusra történő átalakításával lehet megoldani. Az ilyen öntvényeknek nincs futásidejű költsége; csupán abból állnak, hogy a példányt fordításkor kevésbé származtatott típusként tekintik meg.
Ha egy típustag több útvonalon öröklődik ugyanabból az alapfelületről, a rendszer úgy kezeli a típustagot, mintha csak egyszer öröklötték volna. Más szóval a származtatott felület csak egy példányt tartalmaz az egyes típustagok közül, amelyek egy adott alapillesztőtől öröklődnek. Például:
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
Ha egy típustag neve árnyékolt egy elérési úton az öröklési hierarchián keresztül, akkor a név minden útvonalon árnyékolt. Az alábbi példában a IBase.F tag árnyékolt ILeft.F , de nem árnyékolt a következőben 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
A hívás d.F(1) akkor is kiválasztható ILeft.F, ha IBase.F úgy tűnik, hogy nem árnyékolt a hozzáférési útvonal, amelyen keresztül IRightvezet. Mivel a hozzáférési útvonal az IDerived árnyékoktól az árnyékokig ILeftIBaseIBase.F, a tag is árnyékban van a hozzáférési útvonalban, a helyről IDerived a felé.IRightIBase
Árnyék
A származtatott típus újra deklarálásával árnyékot ad egy öröklött típustag nevének. A név árnyékolása nem távolítja el a névvel rendelkező öröklődő típustagokat; csupán az összes ilyen nevű öröklött típustagot elérhetetlenné teszi a származtatott osztályban. Az árnyékolási deklaráció bármilyen típusú entitás lehet.
A túlterheltnél több entitás választhat az árnyékolás két formája közül.
A név szerinti árnyékolás a Shadows kulcsszó használatával van megadva. A név alapján árnyékot viselő entitás mindent elrejt az alaposztályban, beleértve az összes túlterhelést is.
A név és aláírás szerinti árnyékolás a Overloads kulcsszó használatával van megadva. A név és az aláírás alapján árnyékolást végző entitás mindent elrejt az adott név alapján, ugyanazzal az aláírással, mint az entitás. Például:
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
Ha egy metódust név és aláírás alapján árnyékolni egy argumentummal ParamArray , az csak az egyéni aláírást rejti el, nem az összes lehetséges kibontott aláírást. Ez akkor is igaz, ha az árnyékolási módszer aláírása megegyezik az árnyékolt metódus nem használt aláírásával. A következő példa:
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
nyomtat, Basemég akkor is, ha Derived.F ugyanazzal az aláírással rendelkezik, mint a nem kibontott formája Base.F.
Ezzel szemben egy argumentummal rendelkező ParamArray metódus csak az azonos aláírású metódusokat árnyékozza, nem pedig az összes lehetséges kibontott aláírást. A következő példa:
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
nyomtat, Baseannak ellenére Derived.F , hogy kibontott űrlapja ugyanazzal az aláírással rendelkezik, mint Base.Fa .
Árnyékolási módszer vagy tulajdonság, amely nem adja meg Shadows vagy Overloads feltételezi Overloads , hogy a metódus vagy tulajdonság deklarálva Overridesvan, Shadows ellenkező esetben. Ha a túlterhelt entitások egy csoportjának egyik tagja megadja a kulcsszót vagy Overloads a Shadows kulcsszót, mindegyiknek meg kell adnia azt. A Shadows kulcsszavakat és Overloads a kulcsszavakat nem lehet egyszerre megadni. Sem a standard modulban, sem Overloads azokban nem Shadows adható meg; a standard modul tagjai implicit módon árnyéktagokat örökölnek.Object
Érvényes egy olyan típustag nevének árnyékolása, amely az illesztőörökléssel megszorozva öröklődött (és így nem érhető el), így a név elérhetővé válik a származtatott felületen.
Például:
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
Mivel a metódusok árnyékolással öröklődhetnek, az osztály több Overridable , azonos aláírású metódust is tartalmazhat. Ez nem jelent kétértelműséget, mivel csak a legtöbb származtatott módszer látható. Az alábbi példában az C osztályok két DOverridable azonos aláírású metódust tartalmaznak:
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
Itt két Overridable módszer létezik: az egyiket az osztály A , a másikat pedig az osztály Cvezeti be. Az osztály C által bevezetett metódus elrejti az osztálytól Aörökölt metódust. Így az Overrides osztály D deklarációja felülírja az osztály Cáltal bevezetett metódust , és az osztály D nem bírálhatja felül az osztály Aáltal bevezetett metódust . A példa a kimenetet hozza létre:
B.F
B.F
D.F
D.F
A rejtett Overridable metódust úgy hívhatja meg, hogy egy osztálypéldányt D egy kevésbé származtatott típuson keresztül ér el, amelyben a metódus nem rejtett.
Nem érvényes egy MustOverride metódus árnyékolása, mert a legtöbb esetben ez használhatatlanná tenné az osztályt. Például:
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
Ebben az esetben az osztálynak MoreDerived felül kell bírálnia a MustOverride metódust Base.F, de mivel az osztály Derived árnyéka Base.Fvan, ez nem lehetséges. Nem lehet érvényes leszármazottat Deriveddeklarálni.
A külső hatókörből származó nevek árnyékolásával ellentétben az örökölt hatókörből származó akadálymentes név árnyékolása figyelmeztetést eredményez, ahogyan az alábbi példában is látható:
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
Az osztályban Derived a metódus F deklarációja figyelmeztetést eredményez. Az örökölt név árnyékolása kifejezetten nem hiba, mivel ez kizárná az alaposztályok külön fejlődését. Előfordulhat például, hogy a fenti helyzet azért merült fel, mert az osztály Base egy későbbi verziója olyan metódust F vezetett be, amely nem volt jelen az osztály egy korábbi verziójában. Ha a fenti helyzet hiba lett volna, a külön verziójú osztálytár alaposztályának bármilyen módosítása érvénytelenné teheti a származtatott osztályokat.
Az örökölt név árnyékolása által okozott figyelmeztetés kiküszöbölhető a módosító vagy Overloads a Shadows módosító használatával:
Class Base
Public Sub F()
End Sub
End Class
Class Derived
Inherits Base
Public Shadows Sub F() 'OK.
End Sub
End Class
A Shadows módosító jelzi az örökölt tag árnyékolásának szándékát. Nem hiba megadni a módosító vagy Overloads a Shadows módosító nevét, ha nincs árnyékolásra szolgáló típustag neve.
Az új tag deklarációja csak az új tag hatókörén belül árnyékolt egy öröklött tagot, ahogyan az alábbi példában is látható:
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
A fenti példában az osztályban Derived lévő metódus F deklarálása árnyékot ad az osztálytól Baseörökölt metódusnakF, de mivel az osztály Derived új metódusa F rendelkezik Private hozzáféréssel, hatóköre nem terjed ki az osztályra MoreDerived. Így a betárcsázás F()MoreDerived.G érvényes, és meghívja Base.F. Túlterhelt típustagok esetén a rendszer úgy kezeli a túlterhelt típusú tagok teljes készletét, mintha mindegyiknek a legmegfelelőbb hozzáférése lett volna árnyékolás céljából.
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
Ebben a példában annak ellenére, hogy az in Derived deklarációja F() hozzáféréssel Private van deklarálva, a túlterheltség F(Integer) hozzáféréssel Public van deklarálva. Ezért az árnyékolás céljából a be megadott név F úgy lesz kezelve, mintha az lenne Public, így mindkét módszer árnyékot F ad.BaseDerived
Megvalósítás
Implementációs kapcsolat akkor áll fenn, ha egy típus azt deklarálja, hogy egy interfészt implementál, és a típus implementálja a felület összes típustagját. Az adott felületet megvalósító típus átalakítható erre a felületre. Az interfészek nem hozhatók létre, de az interfészek változóinak deklarálása érvényes; az ilyen változók csak az interfészt megvalósító osztályhoz tartozó értékhez rendelhetők hozzá. Például:
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
A többszörösen öröklő típusú tagokkal rendelkező felületet implementáló típusnak továbbra is implementálnia kell ezeket a metódusokat, még akkor is, ha közvetlenül nem érhetők el a implementált felületről. Például:
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
Még MustInherit az osztályoknak is biztosítaniuk kell a implementációkat a implementált felületek összes tagjának, azonban halaszthatják ezeknek a módszereknek a végrehajtását, ha deklarálják őket MustOverride. Például:
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
Egy típus dönthet úgy, hogy újra implementál egy felületet, amelyet az alaptípus implementál. Az interfész újbóli implementálásához a típusnak explicit módon meg kell adnia, hogy implementálja az interfészt. Az illesztőt újra implementáló típus dönthet úgy, hogy a felület tagjainak csak egy részét, de nem az összeset újra implementálja – az újra implementálást nem alkalmazó tagok továbbra is az alaptípus implementálását használják. Például:
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
Ez a példa a következőt nyomtatja:
TestDerived.DerivedTest1
TestBase.Test2
Ha egy származtatott típus olyan felületet implementál, amelynek alapillesztőit a származtatott típus alaptípusai implementálják, a származtatott típus dönthet úgy, hogy csak az alaptípusok által még nem implementált felülettípus-tagokat implementálja. Például:
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
Az interfészmetódusok egy alaptípusban felülírható módszerrel is implementálhatók. Ebben az esetben a származtatott típus felülbírálhatja a felülbírálható módszert, és megváltoztathatja az interfész implementálását. Például:
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
Implementálási módszerek
A típus egy implementált felület típustagját valósítja meg egy záradékkal ellátott Implements metódus megadásával. A két típustagnak azonos számú paramétert kell tartalmaznia, a paraméterek összes típusának és módosítójának egyeznie kell, beleértve az opcionális paraméterek alapértelmezett értékét, a visszatérési típusnak egyeznie kell, és a metódusparaméterekre vonatkozó összes korlátozásnak meg kell egyeznie. Például:
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
Egyetlen módszer tetszőleges számú felülettípus-tagot implementálhat, ha mindegyike megfelel a fenti feltételeknek. Például:
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
Amikor egy metódust általános felületen implementál, a implementálási módszernek meg kell adnia az interfész típusparamétereinek megfelelő típusargumentumokat. Például:
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
Vegye figyelembe, hogy előfordulhat, hogy egy általános felület bizonyos típusú argumentumok esetében nem implementálható.
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
Polimorfizmus
A polimorfizmus lehetővé teszi egy metódus vagy tulajdonság megvalósításának változását. A polimorfizmus esetén ugyanaz a metódus vagy tulajdonság különböző műveleteket hajthat végre a meghívó példány futásidejű típusától függően. A polimorfikus metódusokat vagy tulajdonságokat felülbírálásnak nevezzük. Ezzel szemben egy nem felülírható módszer vagy tulajdonság megvalósítása invariáns; a megvalósítás ugyanaz, akár a metódus vagy a tulajdonság meghívása annak az osztálynak egy példányán történik, amelyben deklarálva van, vagy egy származtatott osztály példánya. Nem felülírható metódus vagy tulajdonság meghívása esetén a példány fordítási ideje a meghatározó tényező. Például:
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
Felülírható módszer is lehet MustOverride, ami azt jelenti, hogy nem biztosít metódustörzset, és felül kell bírálni.
MustOverride metódusok csak osztályokban MustInherit engedélyezettek.
Az alábbi példában az osztály Shape egy olyan geometriai alakzatobjektum absztrakt fogalmát határozza meg, amely képes magát festeni:
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
A Paint módszer az, MustOverride hogy nincs értelmes alapértelmezett implementáció. Az Ellipse osztályok konkrét BoxShape megvalósítások. Mivel ezek az osztályok nem MustInherit, felül kell bírálniuk a metódust Paint , és tényleges megvalósítást kell biztosítaniuk.
Hiba, ha egy alaphozzáférés hivatkozik egy MustOverride metódusra, ahogy az alábbi példa is mutatja:
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
A rendszer hibajelentést ad a MyBase.F() híváshoz, mert egy metódusra MustOverride hivatkozik.
Felülírási módszerek
Egy típus felülírhat egy öröklött felülbírálható metódust egy azonos nevű és aláírású metódus deklarálásával, valamint a deklarációt a Overrides módosítóval való megjelölésével. Az alábbiakban további követelmények vonatkoznak a felülírási módszerekre. Míg a Overridable módszerdeklaráció új módszert vezet be, a Overrides módszerdeklaráció felváltja a módszer öröklött végrehajtását.
Felülrekedő módszer deklarálható NotOverridable, amely megakadályozza a módszer származtatott típusok esetében történő további felülírását. A metódusok gyakorlatilag NotOverridable nem lesznek felülírhatóak a további származtatott osztályokban.
Vegye figyelembe a következő példát:
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
A példában az osztály B két Overrides metódust biztosít: egy olyan metódust F , amely rendelkezik a NotOverridable módosítóval, és egy olyan metódust G , amely nem. A módosító használata megakadályozza az NotOverridable osztály C további felülírási módszerét F.
Felülrekedő módszer is deklarálható MustOverride, még akkor is, ha a felülírás módszere nincs deklarálva MustOverride. Ehhez deklarálni kell a tartalmazó osztályt MustInherit , és a nem deklarált további származtatott osztályoknak felül kell bírálnia a metódust MustInherit . Például:
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
A példában az osztály B felülbírál A.F egy metódust MustOverride . Ez azt jelenti, hogy minden származtatott B osztályt felül kell bírálni F, kivéve, ha azokat is deklarálják MustInherit .
Fordítási időhiba történik, kivéve, ha az alábbiak mindegyike igaz egy felülírási módszerre:
- A deklarációs környezet egyetlen elérhető öröklött metódust tartalmaz, amely ugyanazzal az aláírással és visszatérési típussal rendelkezik (ha van ilyen), mint a felülírási módszer.
- A felülírandó öröklött metódus felülírható. Más szóval a felülírandó öröklődő metódus nem vagy
NotOverridablenemShared. - A deklarált metódus akadálymentességi tartománya megegyezik a felülírandó örökölt metódus akadálymentességi tartományával. Van egy kivétel: egy
Protected Friendmetódusnak felül kell bírálnia egyProtectedmetódust, ha a másik metódus egy másik szerelvényben van, amelyhez a felülírási módszer nem rendelkezikFriendhozzáféréssel. - A felülírási módszer paraméterei megegyeznek a felülírt metódus paramétereinek a ,
ByRefParamArray,ésOptionalmódosítók használataByValtekintetében, beleértve az opcionális paraméterekhez megadott értékeket is. - A felülírási módszer típusparaméterei megfelelnek a felülírt metódus típusparamétereinek a típuskorlátozások tekintetében.
Egy alapszintű általános típusú metódus felülírásakor a felülíró metódusnak meg kell adnia az alaptípus paramétereinek megfelelő típusargumentumokat. Például:
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
Vegye figyelembe, hogy előfordulhat, hogy egy általános osztály felülírható metódusai bizonyos típusú argumentumok esetében nem bírálhatók felül. Ha a metódus deklarálva MustOverridevan, ez azt jelenti, hogy egyes öröklési láncok nem lehetségesek. Például:
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
A felülbírálási deklaráció egy alaphozzáférés használatával érheti el a felülbírált alapmetódust, ahogyan az alábbi példában is látható:
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
A példában az osztály Derived meghívása MyBase.PrintVariables() meghívja az PrintVariables osztályban Basedeklarált metódust. Az alaphozzáférés letiltja a felülbírálási mechanizmust, és egyszerűen nem felülbíráló metódusként kezeli az alapmetódust. Ha a meghívást Derived megírták CType(Me, Base).PrintVariables()volna , az rekurzív módon hívná meg a PrintVariables deklarált Derivedmetódust , nem pedig a deklarált metódust Base.
Egy metódus csak akkor bírálhat felül egy másik metódust, ha módosító van benne Overrides . Minden más esetben az öröklött metódussal azonos aláírású metódus egyszerűen árnyékot ad az örökölt metódusnak, ahogy az alábbi példában látható:
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
A példában az osztály metódusa F nem tartalmaz módosítótOverrides, ezért nem bírálja felül a metódust F az osztálybanBase.Derived Az osztályban Derived lévő metódus F inkább árnyékot ad a metódusnak az osztálybanBase, és figyelmeztetést is jelent, mert a deklaráció nem tartalmaz Shadows módosító vagy Overloads módosító elemet.
Az alábbi példában az osztályban lévő metódus F árnyékot ad az osztálytól Baseörökölt felülírható metódusnakF:Derived
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
Mivel az osztály új metódusa F rendelkezik Private hozzáféréssel, hatóköre csak az osztály törzsét Derived tartalmazza, és nem terjed ki az osztályraMoreDerived.Derived Az osztályban lévő metódus F deklarálása ezért az osztálytól MoreDerivedBaseörökölt metódus F felülbírálható.
Overridable Metódus meghívásakor a rendszer meghívja a példány metódusának leglevezetettebb implementációját a példány típusa alapján, függetlenül attól, hogy a hívás az alaposztály vagy a származtatott osztály metódusához tartozik-e. A metódusok M egy osztályra R vonatkozó legkövetkezettebb implementációját Overridable az alábbiak szerint határozzuk meg:
Ha
Rtartalmazza a bevezető deklarációtOverridableM, akkor ez a legelvezetettebb megvalósítása .MEllenkező esetben, ha
RfelülbírálástMtartalmaz , akkor ez a legelvezetettebb implementáció.MEllenkező esetben a legelvezetettebb implementáció
Mugyanaz, mint a közvetlen alaposztály.R
Hozzáférhetőség
A deklaráció a deklarált entitás akadálymentességét határozza meg. Az entitások akadálymentessége nem változtatja meg az entitás nevének hatókörét. A deklaráció akadálymentességi tartománya az összes olyan deklarációs hely halmaza, amelyben a deklarált entitás elérhető.
Az öt hozzáférési típus a következőPublic: , Protected, FriendProtected Friendés Private.
Public a legmegfelelőbb hozzáférési típus, a négy másik típus pedig a Public. A legkevésbé megengedő hozzáférési típus, Privateés a négy másik hozzáférési típus mind a szuperhalmaza Private.
AccessModifier
: 'Public'
| 'Protected'
| 'Friend'
| 'Private'
| 'Protected' 'Friend'
;
A deklaráció hozzáférési típusa opcionális hozzáférési módosítóval van megadva, amely lehet , , , , vagy az és FriendkombinációjaProtected. PrivateFriendProtectedPublic Ha nincs megadva hozzáférés-módosító, az alapértelmezett hozzáférési típus a deklarációs környezettől függ; az engedélyezett hozzáférési típusok a deklarációs környezettől is függenek.
A módosítóval
Publicdeklarált entitások hozzáféréssel rendelkeznekPublic. Az entitások használatáraPublicnincsenek korlátozások.A módosítóval
Protecteddeklarált entitások hozzáféréssel rendelkeznekProtected.Protectedhozzáférés csak az osztályok tagjain (normál típusú és beágyazott osztályokon) vagy standard modulok és struktúrák tagjainOverridableadható meg (amelyeknek definíció szerint örökölniük kell az osztálytól vagySystem.ValueTypeaz osztálytólSystem.Object). AProtectedtag egy származtatott osztály számára elérhető, feltéve, hogy a tag nem példánytag, vagy a hozzáférés a származtatott osztály egy példányán keresztül történik.Protecteda hozzáférés nem a hozzáférés szuperhalmazaFriend.A módosítóval
Frienddeklarált entitások hozzáféréssel rendelkeznekFriend. A hozzáféréssel rendelkezőFriendentitások csak abban a programban érhetők el, amely tartalmazza az entitásdeklarációt vagy az attribútumon keresztülSystem.Runtime.CompilerServices.InternalsVisibleToAttributehozzáférést kapottFriendszerelvényeket.A módosítókkal
Protected Frienddeklarált entitások rendelkeznek az egyesítőkkelProtectedésFriendhozzáféréssel.A módosítóval
Privatedeklarált entitások hozzáféréssel rendelkeznekPrivate. AzPrivateentitások csak a deklarációs környezeten belül érhetők el, beleértve a beágyazott entitásokat is.
A deklaráció akadálymentessége nem függ a deklarációs környezet akadálymentességétől. A hozzáféréssel Private deklarált típus például tartalmazhat hozzáféréssel rendelkező típustagot Public .
Az alábbi kód a különböző akadálymentességi tartományokat mutatja be:
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
A példában szereplő osztályok és tagok a következő akadálymentességi tartományokkal rendelkeznek:
Az akadálymentességi tartomány
AA.Xkorlátlan.A ,
B,B.X,B.C.YB.C.XB.CB.Yés az azt tartalmazó program akadálymentességi tartománya.A.YAz akadálymentességi tartomány a következő
A.Z:A.A , ,
B.Dés az is akadálymentességi tartományaB.Z, beleértveB.CésB.D.BB.D.YB.D.XAz akadálymentességi tartomány a
B.C.ZkövetkezőB.C: .Az akadálymentességi tartomány a
B.D.ZkövetkezőB.D: .
Ahogy a példa is mutatja, a tagok akadálymentességi tartománya soha nem nagyobb, mint egy tartalmú típus. Például annak ellenére, hogy az összes X tag Public akadálymentességet deklarált, az A.X összes olyan akadálymentességi tartománnyal rendelkezik, amely egy adott típusú korlátozás alá van állítva.
A példánytagokhoz való hozzáférésnek Protected a származtatott típus egy példányán keresztül kell lennie, hogy a nem kapcsolódó típusok ne férhessenek hozzá egymás védett tagjaihoz. Például:
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
A fenti példában az osztály Guest csak akkor rendelkezik hozzáféréssel a védett Password mezőhöz, ha a mező egy példányával Guestvan minősítve. Ez megakadályozza Guest , hogy Password egy objektum mezőihez Employee csak úgy férhessen hozzá, hogy az objektumot a következőre Useröntötte.
Az általános típusok taghozzáférése Protected érdekében a deklarációs környezet típusparamétereket tartalmaz. Ez azt jelenti, hogy egy egy típusargumentumkészlettel rendelkező származtatott típus nem fér hozzá más Protected típusú argumentumokkal rendelkező származtatott típus tagjaihoz. Például:
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
Jegyzet. A C#-nyelv (és esetleg más nyelvek) lehetővé teszi, hogy egy általános típus a megadott típusargumentumoktól függetlenül hozzáférjen a tagokhoz Protected . Ezt figyelembe kell venni a tagokat tartalmazó Protected általános osztályok tervezésekor.
Rendszerösszetevő-típusok
A deklaráció alkotó típusai azok a típusok, amelyekre a deklaráció hivatkozik. Például az állandó típusa, a metódus visszatérési típusa és a konstruktor paramétertípusai mind rendszerösszetevők. A deklaráció egy összetevőtípusának akadálymentességi tartományának meg kell egyeznie a deklaráció akadálymentességi tartományával vagy annak egy szuperhalmazával. Például:
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
Típus- és névtérnevek
Számos nyelvi szerkezethez névteret vagy típust kell megadni; ezek a névtér vagy típus nevének minősített formájával adhatók meg. A minősített név pontokkal elválasztott azonosítók sorozatából áll; az időszak jobb oldalán lévő azonosító feloldása az időszak bal oldalán található azonosító által megadott deklarációs térben történik.
A névtér vagy típus teljes neve olyan minősített név, amely tartalmazza az összes névteret és típust tartalmazó nevet. Más szóval egy névtér vagy típus N.Tteljes neve az, ahol T az entitás neve, és N az azt tartalmazó entitás teljes neve.
Az alábbi példa számos névteret és típusdeklarációt mutat be a hozzájuk tartozó teljes névvel együtt a sorba írt megjegyzésekben.
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
Figyelje meg, hogy az X.Y névtér két különböző helyen van deklarálva a forráskódban, de ez a két részleges deklaráció csak egy X.Y nevű névteret jelent, amely a D és az E osztályt egyaránt tartalmazza.
Bizonyos esetekben a minősített név a kulcsszóval Globalkezdődhet. A kulcsszó a meg nem nevezett legkülső névteret jelöli, amely olyan helyzetekben hasznos, amikor egy deklaráció árnyékol egy burkoló névteret. A Global kulcsszó lehetővé teszi a "menekülést" a legkülső névtérbe ebben a helyzetben. Például:
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
A fenti példában az első metódushívás érvénytelen, mert az azonosító System nem a névtérhezSystem, hanem az osztályhoz Systemkapcsolódik. A névtér elérésének egyetlen módja, System ha Global a legkülső névtérbe menekül.
Globalutasításban vagy Namespace deklarációban Imports nem használható.
Mivel más nyelvek is bevezethetnek olyan típusokat és névtereket, amelyek megfelelnek a nyelv kulcsszavaknak, a Visual Basic felismeri, hogy a kulcsszavak egy minősített név részét képezik, feltéve, hogy egy adott időszakot követnek. Az ily módon használt kulcsszavak azonosítóként lesznek kezelve. A minősített azonosító X.Default.Class például érvényes minősített azonosító, de Default.Class nem.
Minősített névfeloldás névterekhez és -típusokhoz
A minősített névtér vagy az űrlap N.R(Of A)típusneve – ahol R a jobb szélső azonosító szerepel a minősített névben, és A választható típusargumentumlista – az alábbi lépések azt írják le, hogyan állapítható meg, hogy melyik névtérre vagy típusra hivatkozik a minősített név:
A feloldás
Na minősített vagy a nem minősített névfeloldás szabályaival.Ha a
Nhiba megoldása sikertelen, vagy egy típusparaméterre oldódik fel, fordítási időhiba lép fel.Ellenkező esetben, ha
Rmegfelel egy névtér nevének az N-ben, és nem ad meg típusargumentumokat, vagyRegy elérhető típustNugyanazzal a típusparaméterrel egyezik meg, mint a típusargumentumok, akkor a minősített név erre a névtérre vagy típusra hivatkozik.Ellenkező esetben, ha
Negy vagy több standard modult tartalmaz, ésRmegegyezik egy akadálymentes típus nevével ugyanazzal a típusparaméterrel, mint a típusargumentumok, ha vannak ilyenek, pontosan egy standard modulban, akkor a minősített név erre a típusra hivatkozik. HaRaz akadálymentes típusok neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, egynél több standard modulban fordítási időhiba lép fel.Ellenkező esetben fordítási időhiba lép fel.
Jegyzet. Ennek a megoldási folyamatnak az a következménye, hogy a típustagok nem árnyéknévtereket vagy típusokat használnak a névtér vagy a típusnevek feloldásakor.
Névterek és -típusok nem minősített névfeloldása
Ha nem minősített névről R(Of A)van szó – ahol A egy választható típus argumentumlistája – az alábbi lépések azt írják le, hogyan állapítható meg, hogy melyik névtérre hivatkozik, vagy írja be a nem minősített nevet:
Ha az R megegyezik az aktuális metódus egyik típusparaméterének nevével, és nem adott meg típusargumentumokat, akkor a nem minősített név erre a típusparaméterre hivatkozik.
A névhivatkozást tartalmazó beágyazott típusok esetében a legbelső típustól kezdve a legkülső típusig:
- Ha
Rmegegyezik egy típusparaméter nevével az aktuális típusban, és nem adtak meg típusargumentumokat, akkor a nem minősített név erre a típusparaméterre hivatkozik. - Ellenkező esetben, ha
Regy akadálymentes beágyazott típus neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, akkor a nem minősített név erre a típusra hivatkozik.
- Ha
A névhivatkozást tartalmazó beágyazott névterek esetében a legbelső névtértől kezdve a legkülső névtérig:
- Ha
Rmegegyezik egy beágyazott névtér nevével az aktuális névtérben, és nem ad meg típusargumentumlistát, akkor a nem minősített név erre a beágyazott névtérre hivatkozik. - Ellenkező esetben, ha
Regy akadálymentes típus neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen az aktuális névtérben, akkor a nem minősített név erre a típusra hivatkozik. - Ellenkező esetben, ha a névtér egy vagy több akadálymentes standard modult tartalmaz, és
Rmegegyezik egy akadálymentes beágyazott típus nevével ugyanazzal a típusparaméterekkel, mint a típusargumentumok, ha vannak ilyenek, pontosan egy standard modulban, akkor a nem minősített név erre a beágyazott típusra hivatkozik. HaRaz akadálymentes beágyazott típusok neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, egynél több standard modulban fordítási időhiba lép fel.
- Ha
Ha a forrásfájl egy vagy több importálási aliast használ, és
Rmegfelel valamelyikük nevének, akkor a nem minősített név erre az importálási aliasra hivatkozik. Ha típusargumentumlistát ad meg, fordítási időhiba lép fel.Ha a névhivatkozást tartalmazó forrásfájl egy vagy több importálással rendelkezik:
- Ha
Regy akadálymentes típus neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, pontosan egy importálásban, akkor a nem minősített név erre a típusra hivatkozik. HaRegy akadálymentes típus neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, egynél több importálásban, és mindegyik nem azonos típusú, fordítási időhiba lép fel. - Ellenkező esetben, ha nem adott meg típusargumentumlistát, és
Rpontosan egy importálásban egy elérhető típussal egyezik meg egy névtér nevével, akkor a nem minősített név erre a névtérre hivatkozik. Ha nem adott meg típusargumentumlistát, ésRegy olyan névtér nevét egyezik meg, amely több importálásban is elérhető típusokat tartalmaz, és mindegyik nem ugyanaz a névtér, fordítási időhiba lép fel. - Ellenkező esetben, ha az importálások egy vagy több akadálymentes standard modult tartalmaznak, és
Regy akadálymentes beágyazott típus nevét ugyanazzal a típusparaméterekkel egyezik meg, mint a típusargumentumok, ha vannak ilyenek, pontosan egy standard modulban, akkor a nem minősített név erre a típusra hivatkozik. HaRaz akadálymentes beágyazott típusok neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, egynél több standard modulban fordítási időhiba lép fel.
- Ha
Ha a fordítási környezet egy vagy több importálási aliast határoz meg, és
Rmegfelel valamelyikük nevének, akkor a nem minősített név erre az importálási aliasra hivatkozik. Ha típusargumentumlistát ad meg, fordítási időhiba lép fel.Ha a fordítási környezet egy vagy több importálást határoz meg:
- Ha
Regy akadálymentes típus neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, pontosan egy importálásban, akkor a nem minősített név erre a típusra hivatkozik. HaRegy akadálymentes típus neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, egynél több importálás esetén fordítási időhiba lép fel. - Ellenkező esetben, ha nem adott meg típusargumentumlistát, és
Rpontosan egy importálásban egy elérhető típussal egyezik meg egy névtér nevével, akkor a nem minősített név erre a névtérre hivatkozik. Ha nem adott meg típusargumentumlistát, ésRegy olyan névtér nevét egyezik meg, amely egynél több importálásban is elérhető típusokat tartalmaz, fordítási időhiba lép fel. - Ellenkező esetben, ha az importálások egy vagy több akadálymentes standard modult tartalmaznak, és
Regy akadálymentes beágyazott típus nevét ugyanazzal a típusparaméterekkel egyezik meg, mint a típusargumentumok, ha vannak ilyenek, pontosan egy standard modulban, akkor a nem minősített név erre a típusra hivatkozik. HaRaz akadálymentes beágyazott típusok neve megegyezik a típusargumentumokkal azonos számú típusparaméterrel, ha van ilyen, egynél több standard modulban fordítási időhiba lép fel.
- Ha
Ellenkező esetben fordítási időhiba lép fel.
Jegyzet. Ennek a megoldási folyamatnak az a következménye, hogy a típustagok nem árnyéknévtereket vagy típusokat használnak a névtér vagy a típusnevek feloldásakor.
A név általában csak egyszer fordul elő egy adott névtérben. Mivel azonban a névterek több .NET-szerelvényen is deklarálhatók, előfordulhat, hogy két szerelvény azonos teljes névvel definiál egy típust. Ebben az esetben a forrásfájlok aktuális készletében deklarált típust előnyben részesíti a külső .NET-szerelvényben deklarált típus. Ellenkező esetben a név nem egyértelmű, és nincs mód a név egyértelműsítésére.
Változók
A változó egy tárolási helyet jelöl. Minden változónak van egy típusa, amely meghatározza, hogy milyen értékek tárolhatók a változóban. Mivel a Visual Basic egy típusbiztos nyelv, a program minden változója rendelkezik típussal, és a nyelv garantálja, hogy a változókban tárolt értékek mindig a megfelelő típusúak. A változók mindig a típusuk alapértelmezett értékére vannak inicializálva, mielőtt a változóra hivatkozni lehetne. Nem érhető el az nem inicializált memória.
Általános típusok és metódusok
A típusok (a standard modulok és a számozott típusok kivételével) és a metódusok deklarálhatnak típusparamétereket, amelyek olyan típusok, amelyek csak a típus egy példányának deklarálásáig vagy a metódus meghívásáig lesznek megadva. A típusparaméterekkel rendelkező típusokat és metódusokat általános típusoknak és általános metódusoknak is nevezik, mivel a típust vagy metódust általánosan kell írni, anélkül, hogy a típust vagy metódust használó kód konkrét ismeretekkel rendelkezik.
Jegyzet. Jelenleg, bár a metódusok és a meghatalmazottak lehetnek általánosak, a tulajdonságok, az események és az operátorok nem lehetnek általánosak. Használhatnak azonban típusparamétereket az adott osztályból.
Az általános típus vagy metódus szempontjából a típusparaméter olyan helyőrző típus, amely a típus vagy metódus használatakor tényleges típussal lesz kitöltve. A típusargumentumokat a típus vagy metódus típusparaméterei helyettesítik a típus vagy a metódus felhasználási helyén. Egy általános veremosztály például a következőképpen implementálható:
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
Az osztályt Stack(Of ItemType) használó deklarációknak típusargumentumot kell megadniuk a típusparaméterhez ItemType. Ezt a típust az osztályon belül bárhol ItemType kitölti a rendszer:
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
Típusparaméterek
Típusparaméterek megadhatók típus- vagy metódusdeklarációkon. Minden típusparaméter egy azonosító, amely egy típusargumentum helyőrzője, amely egy létrehozott típus vagy metódus létrehozásához van megadva. Ezzel szemben a típusargumentum az a tényleges típus, amely általános típus vagy metódus használata esetén a típusparamétert helyettesíti.
TypeParameterList
: OpenParenthesis 'Of' TypeParameter ( Comma TypeParameter )* CloseParenthesis
;
TypeParameter
: VarianceModifier? Identifier TypeParameterConstraints?
;
VarianceModifier
: 'In' | 'Out'
;
Egy típus- vagy metódusdeklaráció minden típusparamétere meghatároz egy nevet az adott típus vagy metódus deklarációs területén. Így nem lehet ugyanaz a név, mint egy másik típusparaméter, típustag, metódusparaméter vagy helyi változó. Egy típus vagy metódus típusparaméterének hatóköre a teljes típus vagy metódus. Mivel a típusparaméterek hatóköre a teljes típusdeklarációra terjed ki, a beágyazott típusok külső típusparamétereket is használhatnak. Ez azt is jelenti, hogy a típusparamétereket mindig meg kell adni az általános típusokba beágyazott típusok elérésekor:
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
Az osztály többi tagjától eltérően a típusparaméterek nem öröklődnek. A típusparaméterekre csak egyszerű nevük hivatkozhat; más szóval nem minősíthetők a típusnevet tartalmazó névvel. Bár ez rossz programozási stílus, a beágyazott típusparaméterek elrejthetik a külső típusban deklarált tag- vagy típusparamétereket:
Class Outer(Of T)
Class Inner(Of T)
Public t1 As T ' Refers to Inner's T
End Class
End Class
A típusok és metódusok túlterhelhetők a típusparaméterek száma (vagy aritás) alapján, amelyeket a típusok vagy metódusok deklarálnak. A következő nyilatkozatok például jogiak:
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
Típusok esetén a túlterhelések mindig a megadott típusargumentumok számával egyeznek. Ez akkor hasznos, ha az általános és a nem általános osztályokat együtt használja ugyanabban a programban:
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
A típusparamétereken túlterhelt metódusokra vonatkozó szabályokat a metódusok túlterhelésének feloldásáról szóló szakasz ismerteti.
A tartalmú deklaráción belül a típusparaméterek teljes típusnak minősülnek. Mivel a típusparaméterek számos különböző tényleges típusargumentummal hozhatók létre, a típusparaméterek működése és korlátozásai némileg eltérnek a többi típustól az alábbiak szerint:
A típusparaméter nem használható közvetlenül alaposztály vagy interfész deklarálásához.
A típusparaméterekre vonatkozó tagkeresési szabályok a típusparaméterre alkalmazott korlátozásoktól függnek, ha vannak ilyenek.
A típusparaméterek elérhető konverziói a típusparaméterekre alkalmazott korlátozásoktól függnek, ha vannak ilyenek.
Kényszer hiányában
Structureegy típusparaméter által képviselt típussal rendelkező érték összehasonlítható a használattalIsésIsNotaNothing.A típusparaméter csak akkor használható kifejezésben
New, ha a típusparamétert egy vagy egyNewStructurekorlátozás korlátozza.A típusparaméter nem használható egy kifejezésen belüli attribútumkivételen belül
GetType.A típusparaméterek más általános típusokhoz és paraméterekhez is használhatók típusargumentumként.
Az alábbi példa egy általános típus, amely kibővíti az osztályt Stack(Of ItemType) :
Class MyStack(Of ItemType)
Inherits Stack(Of ItemType)
Public ReadOnly Property Size() As Integer
Get
Return CurrentIndex
End Get
End Property
End Class
Amikor egy deklaráció típusargumentumot MyStackad meg, a rendszer ugyanezt a típusargumentumot is alkalmazza Stack .
Típusként a típusparaméterek pusztán fordítási idejű konstrukciók. Futásidőben minden típusparaméter egy olyan futásidejű típushoz van kötve, amelyet egy típusargumentum megadásával adott meg az általános deklarációhoz. Így a típusparaméterrel deklarált változó típusa futásidőben nem általános vagy adott létrehozott típus lesz. A típusparamétereket tartalmazó összes utasítás és kifejezés futásidejű végrehajtása az adott paraméter típusargumentumaként megadott tényleges típust használja.
Típuskorlátozások
Mivel egy típusargumentum bármilyen típus lehet a típusrendszerben, egy általános típus vagy metódus nem tehet feltételezéseket egy típusparaméterről. Így a típusparaméterek tagjai a típus tagjainak minősülnek, mivel minden típus a típusból ObjectObjectszármazik.
Egy ilyen Stack(Of ItemType)gyűjtemény esetében ez a tény nem feltétlenül fontos korlátozás, de lehetnek olyan esetek, amikor egy általános típus feltételezni szeretné a típusargumentumként megadott típusokat.
A típuskorlátozások olyan típusparaméterekre helyezhetők, amelyek korlátozzák, hogy mely típusokat lehet típusparaméterként megadni, és lehetővé teszik, hogy az általános típusok vagy metódusok többet feltételezhessenek a típusparaméterekről.
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
Ebben a példában a típusparamétert csak az DisposableStack(Of ItemType) illesztőt System.IDisposablemegvalósító típusok számára korlátozza. Ennek eredményeképpen implementálhat egy metódust Dispose , amely az üzenetsorban maradt összes objektumot megsemmisíti.
A típuskényszernek a speciális kényszerek Classegyikének kell lennie, Structurevagy Newolyan típusnak T kell lennie, ahol:
Tosztály, interfész vagy típusparaméter.TnemNotInheritable.Tnem az alábbi speciális típusok egyike, vagy az egyiktől öröklődő típus:System.Array, ,System.Delegate,System.MulticastDelegateSystem.EnumvagySystem.ValueType.TnemObject. Mivel minden típus származik,Objectaz ilyen korlátozásnak nincs hatása, ha engedélyezve lenne.Tlegalább olyan elérhetőnek kell lennie, mint a deklarált általános típus vagy metódus.
Egyetlen típusparaméterhez több típuskényszer is megadható, ha a típuskényszereket kapcsos zárójelekbe ({})ágyazja. Egy adott típusparaméterhez csak egy típuskényszer lehet osztály. Hiba, ha egy speciális kényszert Structure egy nevesített osztálykényszerrel vagy speciális Class kényszerrel kombinál.
Class ControlFactory(Of T As {Control, New})
...
End Class
A típuskorlátozások használhatják a tartalmazó típusokat vagy az azt tartalmazó típusparaméterek bármelyikét. A következő példában a kényszer megköveteli, hogy a megadott típusargumentum egy általános felületet implementáljon, amely önmagát használja típusargumentumként:
Class Sorter(Of V As IComparable(Of V))
...
End Class
A speciális típusmegkötés Class a megadott típusargumentumot bármely referenciatípusra korlátozza.
Jegyzet. A speciális típusmegkötést Class egy interfész is kielégítheti. A struktúra pedig implementálhat egy interfészt. Ezért a kényszer (Of T As U, U As Class) egy "T" szerkezettel (amely nem felel meg a Class különleges kényszernek) és az "U" felülettel, amelyet implementál (amely megfelel a Class különleges kényszernek).
A speciális típusmegkötés Structure a megadott típusargumentumot bármely értéktípusra korlátozza, kivéve System.Nullable(Of T).
Jegyzet. A struktúrakorlátozások nem teszik lehetővé System.Nullable(Of T) , hogy ne lehessen típusargumentumként megadni System.Nullable(Of T) magát.
A speciális típusmegkötés New megköveteli, hogy a megadott típusargumentumnak elérhető paraméter nélküli konstruktorsal kell rendelkeznie, és nem deklarálható MustInherit. Például:
Class Factory(Of T As New)
Function CreateInstance() As T
Return New T()
End Function
End Class
Az osztálytípus-korlátozás megköveteli, hogy a megadott típusargumentum legyen az a típus, vagy örökölje azt. Az illesztőtípus-megkötések megkövetelik, hogy a megadott típusargumentum implementálja ezt a felületet. A típusparaméter-kényszerhez a megadott típusargumentumnak az egyező típusparaméterhez megadott összes korlátból kell származnia vagy implementálnia. Például:
Class List(Of T)
Sub AddRange(Of S As T)(collection As IEnumerable(Of S))
...
End Sub
End Class
Ebben a példában a típusparaméter AddRangeS a típusparaméterre TListvan korlátozva. Ez azt jelenti, hogy egy List(Of Control) típusparamétert bármely olyan típusra korlátozna AddRange, amely az adott típustól származik vagy örököl Control.
A típusparaméter-kényszereket Of S As T úgy oldja meg, hogy tranzitív módon hozzáadja az összes Tkényszert Sa speciális kényszereken kívül (Class, Structure, New). Hiba, ha körkörös megkötések vannak (pl. Of S As T, T As S). Hiba egy olyan típusparaméter-kényszer használata, amely maga is rendelkezik a Structure kényszerrel. A korlátozások hozzáadása után előfordulhat, hogy számos különleges helyzet fordulhat elő:
Ha több osztálykényszer létezik, a legelvezetettebb osztály lesz a kényszer. Ha egy vagy több osztálykényszer nem rendelkezik öröklési kapcsolatokkal, a kényszer nem megfelelő, és hiba.
Ha egy típusparaméter egy speciális kényszert kombinál egy
Structurenevesített osztálykényszerrel vagy speciálisClasskényszerrel, az hiba. Az osztálykényszer lehetNotInheritable, amely esetben a rendszer nem fogadja el a kényszer származtatott típusait, és ez hiba.
A típus lehet az alábbi speciális típusok System.Arrayegyike vagy típusa: , System.Delegate, System.MulticastDelegate, System.Enum, vagy System.ValueType. Ebben az esetben a rendszer csak a típust vagy a tőle örökölt típust fogadja el. Az ilyen típusokra korlátozott típusparaméterek csak az operátor által DirectCast engedélyezett átalakításokat használhatják. Például:
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
Ezenkívül a fenti relaxációk egyike miatt egy értéktípusra korlátozott típusparaméter nem tud meghívni az adott értéktípuson definiált metódusokat. Például:
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
Ha a kényszer a helyettesítés után tömbtípusként végződik, bármely kovariantikus tömbtípus is engedélyezett. Például:
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
Az osztály- vagy felületkorlátozással rendelkező típusparaméterek tagjai megegyeznek az adott osztály- vagy felületkényszerrel. Ha egy típusparaméter több korlátozással rendelkezik, akkor a típusparaméter a kényszerek összes tagjának egyesítését tekinti. Ha több kényszerben is vannak azonos nevű tagok, akkor a tagok a következő sorrendben vannak elrejtve: az osztálykényszer elrejti a tagokat a felületi megkötésekben, amelyek elrejtik a tagokat System.ValueType (ha Structure kényszer van megadva), amely elrejti a tagokat.Object Ha egy azonos nevű tag egynél több felületi korlátozásban jelenik meg, a tag nem érhető el (mint több interfészöröklés esetében), és a típusparamétert a kívánt felületre kell leadni. Például:
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
Típusparaméterek típusargumentumként való megadásakor a típusparamétereknek meg kell felelniük az egyező típusparaméterek korlátainak.
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
A korlátozott típusú paraméter értékei használhatók a példánytagok elérésére, beleértve a kényszerben megadott példánymetó módszereket is.
Interface IPrintable
Sub Print()
End Interface
Class Printer(Of V As IPrintable)
Sub PrintOne(v1 As V)
V1.Print()
End Sub
End Class
Típusparaméter eltérése
Egy interfész típusparamétere vagy egy delegált típusdeklaráció opcionálisan megadhat variancia-módosító értéket. A varianciamódosítókkal rendelkező típusparaméterek korlátozzák a típusparaméter használatát az illesztő- vagy delegálási típusban, de lehetővé teszik egy általános felület vagy delegálási típus konvertálását egy másik általános típusra a változatkompatibilis típusargumentumokkal. Például:
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
A varianciamódosítókkal rendelkező típusparaméterekkel rendelkező általános adapterek számos korlátozással rendelkeznek:
Nem tartalmazhatnak paraméterlistát meghatározó eseménydeklarációt (de egyéni eseménydeklaráció vagy delegált típusú eseménydeklaráció engedélyezett).
Nem tartalmazhatnak beágyazott osztályt, struktúrát vagy számba vehető típust.
Jegyzet. Ezek a korlátozások annak a ténynek köszönhetők, hogy az általános típusokba beágyazott típusok implicit módon másolják a szülő általános paramétereit. Beágyazott osztályok, struktúrák vagy számbavételes típusok esetén ezek a típustípusok nem rendelkeznek varianciamódosítókkal a típusparamétereken. Paraméterlistával rendelkező eseménydeklarációk esetén a létrehozott beágyazott delegált osztály zavaró hibákat okozhat, ha egy pozícióban In használt típust (azaz paramétertípust) ténylegesen egy pozícióban (azaz az esemény típusában Out ) használnak.
A Ki módosítóval deklarált típusparaméter a kovariant. A kovariáns típusú paraméter nem hivatalos módon csak kimeneti pozícióban használható – azaz a felületről vagy delegált típusból visszaadott értékben –, és bemeneti pozícióban nem használható. Egy típus T akkor tekinthető érvényesnek, ha:
Tosztály, struktúra vagy számbavételi típus.Tnem általános delegálási vagy felülettípus.Tolyan tömbtípus, amelynek elemtípusa kovariantikusan érvényes.Tolyan típusparaméter, amely nem típusparaméterkéntOutlett deklarálva.Tegy olyan létrehozott interfész- vagy delegálástípusX(Of P1,...,Pn), amely típusargumentumokkal rendelkezikA1,...,An, például:Ha
Piout típusú paraméterként lett deklarálva, akkorAiközösen érvényes.Ha
PiIn típusú paraméterként lett deklarálva, akkorAiaz érvénytelen.
A következőknek közösen kell érvényesnek lenniük egy interfész- vagy delegálási típusban:
Egy interfész alapfelülete.
Függvény vagy delegált típus visszatérési típusa.
A tulajdonság típusa, ha van
Gettartozék.Bármely paraméter típusa
ByRef.
Például:
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
Jegyzet.
Out nem fenntartott szó.
Az In módosítóval deklarált típusparaméter a contravariant. Nem hivatalos módon a contravariant típusú paraméter csak bemeneti pozícióban használható – azaz az interfésznek vagy delegált típusnak átadott érték –, és kimeneti pozícióban nem használható. Egy típus T akkor tekinthető érvényesnek , ha:
Tosztály, struktúra vagy számbavételi típus.Tnem általános meghatalmazott vagy felülettípus.Tolyan tömbtípus, amelynek elemtípusa ellenjavalltan érvényes.TOlyan típusparaméter, amely nem in típusú paraméterként lett deklarálva.Tegy olyan létrehozott interfész- vagy delegálástípusX(Of P1,...,Pn), amely típusargumentumokkal rendelkezikA1,...,An, például:Ha
PitípusparaméterkéntOutlett deklarálva, akkorAiaz érvénytelen.Ha
PitípusparaméterkéntInlett deklarálva, akkorAia kovariantikusan érvényes.
A következőknek érvénytelennek kell lenniük egy interfész- vagy delegálttípusban:
A paraméter típusa.
Típuskorlátozás egy metódustípus-paraméterhez.
A tulajdonság típusa, ha tartozéka
Setvan.Az esemény típusa.
Például:
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
Abban az esetben, ha egy típusnak érvényesnek kell lennie, összhangban és kovariánsan kell lennie (például egy tulajdonságnak egy és Set egy Get tartozékot vagy paramétert ByRef is tartalmaznia kell), a variáns típusú paraméter nem használható.
A ko- és kontra-variancia "gyémánt kétértelműségi problémát" okoz. Vegye figyelembe a következő kódot:
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()
Az osztály C kétféleképpen konvertálhatóIEnumerable(Of Object), mind a kovariáns átalakítássalIEnumerable(Of String), mind a kovariantikus konvertálással.IEnumerable(Of Exception) A CLR nem határozza meg, hogy a két metódus közül melyiket hívja meg c.GetEnumerator()a rendszer. Általánosságban elmondható, hogy ha egy osztályt úgy deklarálnak, hogy két különböző általános argumentummal rendelkező, közös szupertípusú (például ebben az esetben String és Exception közös szupertípussal Objectrendelkező) kovátriai illesztőt implementál, vagy egy osztályt úgy deklarálnak, hogy két különböző, közös altípusú általános argumentummal rendelkező contravariant interfészt implementál, akkor valószínűleg kétértelműség fog felmerülni. A fordító figyelmeztetést ad az ilyen deklarációkra.
Visual Basic language spec