Bővítménymetelyek (Visual Basic)
A bővítménymódszerekkel a fejlesztők új származtatott típus létrehozása nélkül adhatnak hozzá egyéni funkciókat a már definiált adattípusokhoz. A bővítménymetódusok lehetővé teszik olyan metódus írását, amely úgy hívható meg, mintha a meglévő típusú példánymetódus lenne.
Megjegyzések
A bővítménymetódus lehet csak eljárás Sub
vagy Function
eljárás. Bővítménytulajdonságot, mezőt vagy eseményt nem definiálhat. Minden kiterjesztési metódust a névtér bővítményattribútumával <Extension>
System.Runtime.CompilerServices kell megjelölni, és egy modulban kell definiálni. Ha egy bővítménymetódus egy modulon kívül van definiálva, a Visual Basic fordító hibaüzenetet hoz létre BC36551: "A bővítménymetódusok csak modulokban határozhatók meg".
A bővítménymetódus definíciójának első paramétere határozza meg, hogy a metódus melyik adattípust bővíti ki. A metódus futtatásakor az első paraméter a metódust meghívó adattípus példányához lesz kötve.
Az Extension
attribútum csak Visual Basic Module
vagy Sub
Function
. Ha egy Class
vagy többre Structure
alkalmazza, a Visual Basic fordító hibát generál BC36550, a "Bővítmény" attribútum csak a "Modul", az "Al" vagy a "Függvény" deklarációkra alkalmazható.
Példa
Az alábbi példa az Print
adattípus bővítményét String határozza meg. A metódus egy sztring megjelenítésére használja Console.WriteLine
. A metódus paramétere Print
megállapítja, aString
hogy a metódus kiterjeszti az osztályt String .
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()>
Public Sub Print(ByVal aString As String)
Console.WriteLine(aString)
End Sub
End Module
Figyelje meg, hogy a bővítménymetódus definíciója a bővítményattribútummal <Extension()>
van megjelölve. A modul megjelölése, amelyben a metódus definiálva van, nem kötelező, de minden bővítménymetódust meg kell jelölni. System.Runtime.CompilerServices a bővítményattribútum eléréséhez importálni kell.
A bővítménymetelyek csak modulokon belül deklarálhatók. Általában az a modul, amelyben egy bővítménymetódus definiálva van, nem ugyanaz a modul, mint amelyikben meghívják. Ehelyett a bővítménymetódust tartalmazó modult importálja a rendszer, ha szükséges, hogy hatókörbe helyezze. Miután a modul Print
hatókörbe került, a metódus úgy hívható meg, mintha egy szokásos példánymetódus lenne, amely nem vesz fel argumentumokat, például ToUpper
:
Module Class1
Sub Main()
Dim example As String = "Hello"
' Call to extension method Print.
example.Print()
' Call to instance method ToUpper.
example.ToUpper()
example.ToUpper.Print()
End Sub
End Module
A következő példa PrintAndPunctuate
egy bővítmény Stringis, amely ezúttal két paraméterrel van definiálva. Az első paraméter megállapítja, aString
hogy a bővítménymetódus kiterjeszthető String. A második paraméter punc
az írásjelek sztringje, amelyet argumentumként ad át a metódus meghívásakor. A metódus megjeleníti a sztringet, majd az írásjeleket.
<Extension()>
Public Sub PrintAndPunctuate(ByVal aString As String,
ByVal punc As String)
Console.WriteLine(aString & punc)
End Sub
A metódus meghívásához sztringargumentumot kell küldeni a következőhöz punc
: example.PrintAndPunctuate(".")
Az alábbi példa bemutatja Print
és PrintAndPunctuate
definiálja és meghívja. System.Runtime.CompilerServices a definíciómodulba importálja a bővítményattribútumhoz való hozzáférés engedélyezéséhez.
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()>
Public Sub Print(aString As String)
Console.WriteLine(aString)
End Sub
<Extension()>
Public Sub PrintAndPunctuate(aString As String, punc As String)
Console.WriteLine(aString & punc)
End Sub
End Module
Ezután a bővítménymetelyek hatókörbe kerülnek, és a következőt hívják:
Imports ConsoleApplication2.StringExtensions
Module Module1
Sub Main()
Dim example As String = "Example string"
example.Print()
example = "Hello"
example.PrintAndPunctuate(".")
example.PrintAndPunctuate("!!!!")
End Sub
End Module
Mindössze annyit kell tenni, hogy képes legyen futtatni ezeket a vagy hasonló bővítménymetszeteket, az, hogy hatókörben vannak. Ha a bővítménymetódust tartalmazó modul hatókörben van, akkor az látható az IntelliSense-ben, és úgy hívható meg, mintha egy szokásos példánymetódus lenne.
Figyelje meg, hogy a metódusok meghívásakor a rendszer nem küld argumentumot az első paraméterhez. Az aString
előző metódusdefiníciók paramétere az őket meghívó String
példányhoz example
van kötve. A fordító az első paraméternek küldött argumentumként fog használni example
.
Ha a bővítménymetódus egy olyan objektumhoz van meghívva, amely a következőre Nothing
van állítva, a bővítménymetódus végrehajtja a parancsot. Ez nem vonatkozik a szokásos példány metódusokra. A bővítménymetódusban kifejezetten kereshet Nothing
.
Bővíthető típusok
A Visual Basic paraméterlistában megjeleníthető legtöbb típushoz definiálhat bővítménymetódusokat, beleértve a következőket:
- Osztályok (referenciatípusok)
- Struktúrák (értéktípusok)
- Interfészek
- Delegáltak
- ByRef és ByVal argumentumok
- Általános metódusparaméterek
- Tömbök
Mivel az első paraméter a bővítménymetódus által kiterjesztett adattípust adja meg, kötelező megadni, és nem választható. Emiatt Optional
a paraméterek és ParamArray
paraméterek nem lehetnek az első paraméter a paraméterlistában.
A bővítménymetszeteket nem tekintjük késői kötésnek. A következő példában az utasítás anObject.PrintMe()
kivételt MissingMemberException hoz létre, ugyanaz a kivétel, amely akkor jelenik meg, ha a második PrintMe
bővítménymetódus definícióját törölték.
Option Strict Off
Imports System.Runtime.CompilerServices
Module Module4
Sub Main()
Dim aString As String = "Initial value for aString"
aString.PrintMe()
Dim anObject As Object = "Initial value for anObject"
' The following statement causes a run-time error when Option
' Strict is off, and a compiler error when Option Strict is on.
'anObject.PrintMe()
End Sub
<Extension()>
Public Sub PrintMe(ByVal str As String)
Console.WriteLine(str)
End Sub
<Extension()>
Public Sub PrintMe(ByVal obj As Object)
Console.WriteLine(obj)
End Sub
End Module
Ajánlott eljárások
A bővítménymetelyek kényelmes és hatékony módot biztosítanak egy meglévő típus kiterjesztésére. A sikeres használatukhoz azonban érdemes megfontolni néhány szempontot. Ezek a szempontok elsősorban az osztálykódtárak szerzőire vonatkoznak, de hatással lehetnek a bővítménymetelyeket használó alkalmazásokra.
Általában a nem saját típusokhoz hozzáadott bővítménymetelyek sebezhetőbbek, mint az Ön által vezérelt típusokhoz hozzáadott bővítménymetelyek. A nem saját osztályokban számos olyan dolog fordulhat elő, amely zavarhatja a bővítménymetodálokat.
Ha létezik olyan akadálymentes példánytag, amely rendelkezik olyan aláírással, amely kompatibilis a hívó utasítás argumentumaival, és nincs szükség az argumentumról paraméterre történő konvertálás szűkítésére, a rendszer a példánymetódust használja a bővítménymetódusok előnyben részesítésére. Ezért ha egy adott időpontban egy megfelelő példánymetódus van hozzáadva egy osztályhoz, előfordulhat, hogy egy meglévő bővítménytag, amelyre támaszkodik, elérhetetlenné válhat.
A bővítménymetódus szerzője nem akadályozhatja meg, hogy más programozók ütköző bővítménymetódusokat írjanak, amelyek elsőbbséget élvezhetnek az eredeti kiterjesztéssel szemben.
A robusztusságot úgy javíthatja, hogy a bővítménymódszereket a saját névterükbe helyezi. A kódtár felhasználói ezután hozzáadhatnak egy névteret, vagy kizárhatják azt, vagy választhatnak a névterek között, a tár többi részétől elkülönítve.
Biztonságosabb lehet az interfészek kiterjesztése, mint az osztályok kiterjesztése, különösen akkor, ha nem rendelkezik a felülettel vagy az osztályokkal. A felület módosítása minden olyan osztályt érint, amely implementálja azt. Ezért előfordulhat, hogy a szerző kevésbé valószínű, hogy metódusokat ad hozzá vagy módosít egy felületen. Ha azonban egy osztály két olyan felületet implementál, amelyek azonos aláírású bővítménymetódusokkal rendelkeznek, egyik bővítménymetódus sem látható.
Bontsa ki a legspecifikusabb típust. A típusok hierarchiájában, ha olyan típust választ ki, amelyből sok más típus származik, a példánymetodalmok vagy más bővítménymetelyek bevezetésének több lehetősége is van, amelyek zavarhatják az Önét.
Bővítménymetelyek, példánymódszerek és tulajdonságok
Ha egy hatókörön belüli példány olyan aláírással rendelkezik, amely kompatibilis a hívási utasítás argumentumaival, a rendszer a példánymetódust választja a bővítménymetódusok előnyben részesítése érdekében. A példánymetódus akkor is elsőbbséget élvez, ha a bővítménymetódus jobb egyezés. Az alábbi példában egy olyan példánymetódus ExampleMethod
szerepel, ExampleClass
amelynek egy típusa Integer
van. A bővítménymetódus ExampleMethod
kiterjeszthető ExampleClass
, és egy típusparamétert Long
is használ.
Class ExampleClass
' Define an instance method named ExampleMethod.
Public Sub ExampleMethod(ByVal m As Integer)
Console.WriteLine("Instance method")
End Sub
End Class
<Extension()>
Sub ExampleMethod(ByVal ec As ExampleClass,
ByVal n As Long)
Console.WriteLine("Extension method")
End Sub
A következő kód első hívása ExampleMethod
meghívja a bővítménymetódust, mert arg1
az Long
csak a Long
bővítménymetódus paraméterével kompatibilis. A második hívásnak ExampleMethod
argumentuma Integer
van, arg2
és meghívja a példány metódusát.
Sub Main()
Dim example As New ExampleClass
Dim arg1 As Long = 10
Dim arg2 As Integer = 5
' The following statement calls the extension method.
example.exampleMethod(arg1)
' The following statement calls the instance method.
example.exampleMethod(arg2)
End Sub
Most fordítsa vissza a paraméterek adattípusait a két módszerben:
Class ExampleClass
' Define an instance method named ExampleMethod.
Public Sub ExampleMethod(ByVal m As Long)
Console.WriteLine("Instance method")
End Sub
End Class
<Extension()>
Sub ExampleMethod(ByVal ec As ExampleClass,
ByVal n As Integer)
Console.WriteLine("Extension method")
End Sub
Ezúttal a kód Main
mindkét alkalommal meghívja a példánymetódust. Ennek az az oka, hogy mindkét arg1
esetben a példánymetódus a bővítménymetódussal szemben elsőbbséget élvez, és arg2
mindkettőre kiterjeszti a konvertálást Long
.
Sub Main()
Dim example As New ExampleClass
Dim arg1 As Long = 10
Dim arg2 As Integer = 5
' The following statement calls the instance method.
example.ExampleMethod(arg1)
' The following statement calls the instance method.
example.ExampleMethod(arg2)
End Sub
Ezért a bővítménymetódus nem helyettesítheti a meglévő példánymetódusokat. Ha azonban egy bővítménymetódus neve megegyezik egy példánymetódus nevével, de az aláírások nem ütköznek, mindkét metódus elérhető. Ha például az osztály ExampleClass
olyan metódust ExampleMethod
tartalmaz, amely nem tartalmaz argumentumokat, akkor az azonos nevű, de eltérő aláírású bővítménymetódusok engedélyezettek, ahogyan az alábbi kódban is látható.
Imports System.Runtime.CompilerServices
Module Module3
Sub Main()
Dim ex As New ExampleClass
' The following statement calls the extension method.
ex.ExampleMethod("Extension method")
' The following statement calls the instance method.
ex.ExampleMethod()
End Sub
Class ExampleClass
' Define an instance method named ExampleMethod.
Public Sub ExampleMethod()
Console.WriteLine("Instance method")
End Sub
End Class
<Extension()>
Sub ExampleMethod(ByVal ec As ExampleClass,
ByVal stringParameter As String)
Console.WriteLine(stringParameter)
End Sub
End Module
A kód kimenete a következő:
Extension method
Instance method
A tulajdonságok esetében egyszerűbb a helyzet: ha egy bővítménymetódus neve megegyezik a kiterjesztett osztály tulajdonságával, a bővítménymetódus nem látható, és nem érhető el.
A bővítménymetódus elsőbbsége
Ha két azonos aláírással rendelkező bővítménymetely van hatókörben és elérhető, a rendszer meghívja a magasabb elsőbbséget élvező metódust. A bővítménymetódus elsőbbsége a metódus hatókörbe helyezéséhez használt mechanizmuson alapul. Az alábbi listában a rangsor hierarchiája látható a legmagasabbtól a legalacsonyabbig.
Az aktuális modulban definiált bővítménymetelyek.
Az aktuális névtér adattípusaiban vagy bármely szülőjében definiált bővítménymetelyek, amelyeknél a gyermeknévterek elsőbbséget élveznek a szülőnévtereknél.
Az aktuális fájl bármely típusimportálásán belül definiált bővítménymetelyek.
Az aktuális fájl bármely névtérimportálásán belül definiált bővítménymetelyek.
A projektszintű importálásokon belül definiált bővítménymetelyek.
A projektszintű névtérimportálásokon belül definiált bővítménymetelyek.
Ha az elsőbbség nem oldja meg a kétértelműséget, a teljes névvel megadhatja a hívott metódust. Ha a Print
korábbi példában szereplő metódus egy nevesített StringExtensions
modulban van definiálva, akkor a teljes név helyett example.Print()
a teljes név szerepelStringExtensions.Print(example)
.