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


Kiterjesztési metódusok (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

Kiterjesztési metódus csak eljárás Sub vagy Function lehet. 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, Sub vagy Function esetén alkalmazható. Ha egy Class vagy Structure-re alkalmazza, a Visual Basic fordító hibát ad BC36550, "a 'Extension' attribútum csak a 'Module', 'Sub' vagy 'Function' 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, PrintAndPunctuate, szintén egy bővítmény String, ezúttal két paraméterrel definiálva. Az első paraméter megállapítja, aStringhogy a bővítménymetódus kiterjeszthető String. A második paraméter, punc, egy írásjelekből álló sztringnek van szánva, amelyet argumentumként ad át, amikor a metódust meghívják. 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 ahhoz, hogy képes legyen futtatni ezeket vagy hasonló bővítménymódszereket, hogy hatókörben legyenek. 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ó example példányhoz Stringvan 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 kiterjesztés metódusban kifejezetten ellenőrizheti a 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)
  • Felületek
  • 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 kiterjesztési metódusokat nem vesszük figyelembe a késői kötés során. 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. Nem saját tulajdonú osztályokban több olyan dolog is előfordulhat, amely zavarhatja a kiterjesztési metódusokat.

  • 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ó.

  • Terjeszd 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.

Kiterjesztési metódusok, példány metódusok é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 kiterjesztési metódus jobb illeszkedés. Az alábbi példában ExampleClass egy ExampleMethod nevű példánymetódust tartalmaz, amelynek egy paramétere van Integer típusú. 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ódban az első ExampleMethod hívás a bővítménymetódust hívja meg, mert arg1Long, és csak a bővítménymetódus Long 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 mind arg1, mind arg2 képes bővülő konverziót végrehajtani Long-re, és mindkét esetben a példánymetódus elsőbbséget élvez a bővítési metódussal szemben.

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ármelyik szülőnévtérben definiált bővítménymódszerek, ahol a gyermeknévterek magasabb prioritást élveznek, mint a szülőnévterek.

  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 teljesen kvalifikált név megadásával specifikálhatja a hívott metódust. Ha a Print metódus a korábbi példában egy StringExtensions nevű modulban van definiálva, akkor a teljes név StringExtensions.Print(example), nem pedig example.Print().

Lásd még