Dela via


Tilläggsmetoder (Visual Basic)

Med tilläggsmetoder kan utvecklare lägga till anpassade funktioner i datatyper som redan har definierats utan att skapa en ny härledd typ. Med tilläggsmetoder kan du skriva en metod som kan anropas som om det vore en instansmetod av den befintliga typen.

Kommentarer

En tilläggsmetod kan bara vara en Sub procedur eller en Function procedur. Du kan inte definiera en tilläggsegenskap, ett fält eller en händelse. Alla tilläggsmetoder måste markeras med tilläggsattributet System.Runtime.CompilerServices<Extension> från namnområdet och måste definieras i en modul. Om en tilläggsmetod definieras utanför en modul genererar Visual Basic-kompilatorn fel BC36551, "Tilläggsmetoder kan endast definieras i moduler".

Den första parametern i en tilläggsmetoddefinition anger vilken datatyp metoden utökar. När metoden körs är den första parametern bunden till den instans av datatypen som anropar metoden.

Attributet Extension kan endast tillämpas på visual basic Module, Subeller Function. Om du tillämpar den på en Class eller en Structuregenererar Visual Basic-kompilatorn fel BC36550, attributet "Extension" kan endast tillämpas på deklarationer av modul, under eller funktion.

Exempel

I följande exempel definieras ett Print tillägg till String datatypen. Metoden använder Console.WriteLine för att visa en sträng. Parametern för Print metoden, aString, anger att metoden utökar String klassen.

Imports System.Runtime.CompilerServices

Module StringExtensions

    <Extension()> 
    Public Sub Print(ByVal aString As String)
        Console.WriteLine(aString)
    End Sub

End Module

Observera att tilläggsmetoddefinitionen har markerats med tilläggsattributet <Extension()>. Det är valfritt att markera modulen där metoden definieras, men varje tilläggsmetod måste markeras. System.Runtime.CompilerServices måste importeras för att få åtkomst till tilläggsattributet.

Tilläggsmetoder kan endast deklareras i moduler. Vanligtvis är modulen där en tilläggsmetod definieras inte samma modul som den där den anropas. I stället importeras modulen som innehåller tilläggsmetoden, om det behövs, för att föra in den i omfånget. När modulen som innehåller Print finns i omfånget kan metoden anropas som om det vore en vanlig instansmetod som inte tar några argument, till exempel 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

Nästa exempel, PrintAndPunctuate, är också ett tillägg till String, den här gången definierat med två parametrar. Den första parametern, aString, anger att tilläggsmetoden utökar String. Den andra parametern, punc, är avsedd att vara en sträng med skiljetecken som skickas som ett argument när metoden anropas. Metoden visar strängen följt av skiljetecken.

<Extension()> 
Public Sub PrintAndPunctuate(ByVal aString As String, 
                             ByVal punc As String)
    Console.WriteLine(aString & punc)
End Sub

Metoden anropas genom att skicka ett strängargument för punc: example.PrintAndPunctuate(".")

I följande exempel visas Print och PrintAndPunctuate definieras och anropas. System.Runtime.CompilerServices importeras i definitionsmodulen för att ge åtkomst till tilläggsattributet.

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

Därefter tas tilläggsmetoderna in i omfånget och anropas:

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

Allt som krävs för att kunna köra dessa eller liknande tilläggsmetoder är att de finns i omfånget. Om modulen som innehåller en tilläggsmetod finns i omfånget visas den i IntelliSense och kan anropas som om det vore en vanlig instansmetod.

Observera att när metoderna anropas skickas inget argument in för den första parametern. Parametern aString i de tidigare metoddefinitionerna är bunden till example, instansen av String som anropar dem. Kompilatorn använder example som argument som skickas till den första parametern.

Om en tilläggsmetod anropas för ett objekt som är inställt på Nothingkörs tilläggsmetoden. Detta gäller inte för vanliga instansmetoder. Du kan uttryckligen söka efter Nothing i tilläggsmetoden.

Typer som kan utökas

Du kan definiera en tilläggsmetod för de flesta typer som kan representeras i en Visual Basic-parameterlista, inklusive följande:

  • Klasser (referenstyper)
  • Strukturer (värdetyper)
  • Gränssnitt
  • Delegeringar
  • ByRef- och ByVal-argument
  • Allmänna metodparametrar
  • Matriser

Eftersom den första parametern anger den datatyp som tilläggsmetoden utökar krävs den och kan inte vara valfri. Därför Optional kan parametrar och ParamArray parametrar inte vara den första parametern i parameterlistan.

Tilläggsmetoder beaktas inte i sen bindning. I följande exempel genererar -instruktionen anObject.PrintMe() ett MissingMemberException undantag, samma undantag som du skulle se om den andra PrintMe tilläggsmetoddefinitionen togs bort.

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

Bästa praxis

Tilläggsmetoder är ett bekvämt och kraftfullt sätt att utöka en befintlig typ. Men för att kunna använda dem på ett bra sätt finns det några saker att tänka på. Dessa överväganden gäller främst för författare av klassbibliotek, men de kan påverka alla program som använder tilläggsmetoder.

De flesta tilläggsmetoder som du lägger till i typer som du inte äger är mer sårbara än tilläggsmetoder som läggs till i typer som du kontrollerar. Ett antal saker kan inträffa i klasser som du inte äger och som kan störa dina tilläggsmetoder.

  • Om det finns någon tillgänglig instansmedlem som har en signatur som är kompatibel med argumenten i anropsinstrukturen, utan att några begränsade konverteringar krävs från argument till parameter, används instansmetoden i stället för någon tilläggsmetod. Om en lämplig instansmetod läggs till i en klass någon gång kan därför en befintlig tilläggsmedlem som du förlitar dig på bli otillgänglig.

  • Författaren till en tilläggsmetod kan inte hindra andra programmerare från att skriva motstridiga tilläggsmetoder som kan ha företräde framför det ursprungliga tillägget.

  • Du kan förbättra robustheten genom att placera tilläggsmetoder i deras eget namnområde. Användare av biblioteket kan sedan inkludera ett namnområde eller exkludera det, eller välja bland namnområden, separat från resten av biblioteket.

  • Det kan vara säkrare att utöka gränssnitt än att utöka klasser, särskilt om du inte äger gränssnittet eller klassen. En ändring i ett gränssnitt påverkar varje klass som implementerar det. Det kan därför vara mindre troligt att författaren lägger till eller ändrar metoder i ett gränssnitt. Men om en klass implementerar två gränssnitt som har tilläggsmetoder med samma signatur visas ingen tilläggsmetod.

  • Utöka den mest specifika typen du kan. Om du i en hierarki av typer väljer en typ som många andra typer härleds från, finns det lager av möjligheter för introduktion av instansmetoder eller andra tilläggsmetoder som kan störa din.

Tilläggsmetoder, instansmetoder och egenskaper

När en instansmetod i omfånget har en signatur som är kompatibel med argumenten för en anropande instruktion, väljs instansmetoden i stället för någon tilläggsmetod. Instansmetoden har företräde även om tilläggsmetoden är en bättre matchning. I följande exempel ExampleClass innehåller en instansmetod med namnet ExampleMethod som har en parameter av typen Integer. Tilläggsmetoden ExampleMethod utökar ExampleClassoch har en parameter av typen Long.

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

Det första anropet till ExampleMethod i följande kod anropar tilläggsmetoden eftersom arg1 är Long och endast är kompatibel med parametern Long i tilläggsmetoden. Det andra anropet till ExampleMethod har ett Integer argument, arg2, och anropar instansmetoden.

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

Återställ nu datatyperna för parametrarna i de två metoderna:

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

Den här gången anropar koden i Main instansmetoden båda gångerna. Det beror på att både arg1 och arg2 har en bredare konvertering till Long, och instansmetoden har företräde framför tilläggsmetoden i båda fallen.

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

Därför kan inte en tilläggsmetod ersätta en befintlig instansmetod. Men när en tilläggsmetod har samma namn som en instansmetod men signaturerna inte står i konflikt kan båda metoderna nås. Om klassen ExampleClass till exempel innehåller en metod med namnet ExampleMethod som inte tar några argument tillåts tilläggsmetoder med samma namn, men olika signaturer tillåts, enligt följande kod.

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

Utdata från den här koden är följande:

Extension method
Instance method

Situationen är enklare med egenskaper: om en tilläggsmetod har samma namn som en egenskap för den klass som den utökar, visas inte tilläggsmetoden och kan inte nås.

Prioritet för tilläggsmetod

När två tilläggsmetoder som har identiska signaturer finns i omfånget och är tillgängliga anropas den med högre prioritet. En tilläggsmetods prioritet baseras på den mekanism som används för att föra in metoden i omfånget. I följande lista visas prioritetshierarkin, från högsta till lägsta.

  1. Tilläggsmetoder som definierats i den aktuella modulen.

  2. Tilläggsmetoder som definierats i datatyper i det aktuella namnområdet eller någon av dess överordnade, med underordnade namnområden som har högre prioritet än överordnade namnområden.

  3. Tilläggsmetoder som definierats i alla typer av importer i den aktuella filen.

  4. Tilläggsmetoder som definierats i alla namnområdesimporter i den aktuella filen.

  5. Tilläggsmetoder som definierats i alla importer av projektnivåtyper.

  6. Tilläggsmetoder som definierats i alla namnområdesimporter på projektnivå.

Om prioriteten inte löser tvetydigheten kan du använda det fullständigt kvalificerade namnet för att ange den metod som du anropar. Print Om metoden i det tidigare exemplet definieras i en modul med namnet StringExtensionsär StringExtensions.Print(example) det fullständigt kvalificerade namnet i stället för example.Print().

Se även