Megosztás a következőn keresztül:


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 Modulevagy SubFunction. Ha egy Class vagy többre Structurealkalmazza, 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, aStringhogy 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 PrintAndPunctuateegy bővítmény Stringis, amely ezúttal két paraméterrel van definiálva. Az első paraméter megállapítja, aStringhogy a bővítménymetódus kiterjeszthető String. A második paraméter puncaz í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 examplevan 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 Nothingvan á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 Integervan. A bővítménymetódus ExampleMethod kiterjeszthető ExampleClass, és egy típusparamétert Longis 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.

  1. Az aktuális modulban definiált bővítménymetelyek.

  2. 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.

  3. Az aktuális fájl bármely típusimportálásán belül definiált bővítménymetelyek.

  4. Az aktuális fájl bármely névtérimportálásán belül definiált bővítménymetelyek.

  5. A projektszintű importálásokon belül definiált bővítménymetelyek.

  6. 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 StringExtensionsmodulban van definiálva, akkor a teljes név helyett example.Print()a teljes név szerepelStringExtensions.Print(example).

Lásd még