Udostępnij za pośrednictwem


Metody rozszerzeń (Visual Basic)

Metody rozszerzające umożliwiają programistom dodawanie niestandardowych funkcji do zdefiniowanych typów danych, bez tworzenia nowego typu pochodnego.Metody rozszerzające umożliwiają napisanie metody, która może być wywołana tak, jakby była wystąpieniem metody istniejącego typu.

Uwagi

Metoda rozszerzenia może być tylko Sub procedury lub Function procedury.Nie można zdefiniować rozszerzenia, właściwości, pola lub zdarzenia.Wszystkie metody rozszerzenia muszą być oznaczone atrybutem rozszerzenia <Extension()> z System.Runtime.CompilerServices przestrzeni nazw.

Pierwszy parametr w definicji metody rozszerzenie określa typ danych, które rozszerza metoda.Kiedy metoda jest uruchomiona, pierwszy parametr jest powiązany do wystąpienia typu danych, który wywołuje tę metodę.

Przykład

Opis

W poniższym przykładzie zdefiniowano Print rozszerzenia dla typu danych String.Metoda używa Console.WriteLine do wyświetlenia ciągu.Parametr metody Print, aString, ustala, że metoda rozszerza klasę String.

Imports System.Runtime.CompilerServices

Module StringExtensions

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

End Module

Należy zauważyć, że definicja metody rozszerzenia jest oznaczona atrybutem rozszerzenia <Extension()>.Oznaczanie modułu, w którym metoda jest określona jest opcjonalne, ale każda metoda rozszerzająca musi być oznaczona.System.Runtime.CompilerServices muszą być importowane w celu uzyskania dostępu do atrybutu rozszerzenia.

Metody rozszerzające można określić tylko w modułach.Typowo, moduł w którym metoda rozszerzeń jest zdefiniowana nie jest tym samym modułem, w którym jest wywoływana.Zamiast tego, moduł, który zawiera metodę rozszerzająca jest importowany, w razie potrzeby, w celu dostosowania go do zakresu.Po tym jak moduł, który zawiera Print jest w zasięgu, metoda może być wywoływana tak, jakby była to metoda zwykłego wystąpienia, która nie przyjmuje żadnych argumentów, takich jak 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

Następny przykład, PrintAndPunctuate, to także rozszerzenie String, tym razem zdefiniowane za pomocą dwóch parametrów.Pierwszy parametr, aString, określa, że metoda rozszerzenia rozszerza String.Drugi parametr, punc, ma być ciągiem znaków interpunkcyjnych, który jest uznawany za argument przy wywołaniu metody.Metoda wyświetla ciąg, po którym następują znaki interpunkcyjne.

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

Metoda jest wywoływana przez wysłanie argumentu ciągu dla punc: example.PrintAndPunctuate(".")

W poniższym przykładzie pokazano zdefiniowane i wywoływane Print i PrintAndPunctuate.System.Runtime.CompilerServices jest importowany w module definicji w celu umożliwienia dostępu do atrybutu rozszerzenia.

Kod

Imports System.Runtime.CompilerServices

Module StringExtensions

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

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

End Module

Następnie metody rozszerzające są dostosowane do zakresu i wywołane.

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

Komentarze

Wszystko co jest wymagane, aby można było uruchomić te lub podobne metody rozszerzenia to to, aby były one w zakresie.Jeśli moduł, który zawiera metodę rozszerzającą znajdującą się w zakresie, jest widoczny w technologii IntelliSense i może być wywoływany tak, jakby był metodą instancji zwykłej.

Należy zauważyć, że gdy metody są wywołane, żaden argument nie jest wysyłany jako pierwszy parametr.Parametr aString w definicji poprzedniej metody jest związany z example, wystąpieniem String, które je wywołuje.Kompilator będzie używać example jako argumentu wysyłanego do pierwszego parametru.

Jeśli metoda rozszerzająca zostanie wywołana dla obiektu, który jest ustawiony na Nothing, metoda rozszerzająca zostanie wykonana.Nie dotyczy to metod zwykłego wystąpienia.Możesz jawnie szukać Nothing w metodzie rozszerzenia.

Typy, które można rozszerzyć

Możesz zdefiniować metodę rozszerzenia w większości typów, które mogą być przedstawione na liście Visual Basic, łącznie z poniższymi:

  • Klasy (typy odwołań)

  • Struktury (typy wartości)

  • Interfejsy

  • Obiekty delegowane

  • Argumenty ByRef i ByVal

  • Parametry metody ogólnej

  • Tablice

Ponieważ pierwszy parametr określa typ danych, który rozszerza metoda rozszerzenia, jest wymagany i nie może być opcjonalny.Z tego powodu parametry Optional i ParamArray nie mogą być pierwszym parametrem na liście parametrów.

Metody rozszerzające nie są uwzględniane w późnym wiązaniu.W poniższym przykładzie instrukcja anObject.PrintMe() podnosi wyjątek MissingMemberException, ten sam wyjątek, który zostałby wyświetlony, gdyby definicja drugiej metody rozszerzającej PrintMe została usunięta.

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

Najważniejsze wskazówki

Metody rozszerzające to wygodny, zaawansowany sposób rozszerzenia istniejącego typu.Aby ich używać, należy jednak rozważyć pewne kwestie.Te zagadnienia dotyczą głównie autorów bibliotek klas, jednak mogą mieć wpływ na każdą aplikację, która wykorzystuje metody rozszerzeń.

Najogólniej mówiąc, metody rozszerzające, które można dodać do typów, których użytkownik nie posiadaj są bardziej narażone niż metody rozszerzające dodane do typów, które można kontrolować.Kilka rzeczy, mogą wystąpić w klasach, których nie jesteś właścicielem, które mogą zakłócać twoje rozszerzenia metody.

  • Jeśli istnieje jakikolwiek dostępny członek wystąpienia, którego podpis jest zgodny z argumentami w instrukcji wywołujące, bez konwersji zawężającej wymaganej od argumentu do parametru, użyta metoda wystąpienia zostanie użyta zamiast dowolnej metody rozszerzającej.Tym samym, jeżeli odpowiednia metoda wystąpienia jest dodana do klasy w jakimś momencie, istniejący element członkowski rozszerzenia, na którym polegasz, może stać się niedostępny.

  • Autor metody rozszerzenia nie może uniemożliwić innym programistom pisania niezgodnych metod rozszerzeń, które mogą mieć pierwszeństwo nad oryginalnym rozszerzeniem.

  • Możesz ulepszyć odporność umieszczając metody rozszerzeń w ich przestrzeniach nazw.Konsumenci biblioteki mogą następnie włączyć obszar nazw lub wykluczyć go lub wybrać wśród obszarów nazw, niezależnie od pozostałej części biblioteki.

  • Bezpieczniejsze może być rozszerzenie interfejsów niż rozszerzenie klas, zwłaszcza, jeśli nie posiadasz interfejsu lub klasy.Zmiany w interfejsie dotyczą każdej klasy, która implementuje go.Tym samym, jest mniej prawdopodobne, że autor doda lub zmienia metodę w interfejsie.Jeśli jednak klasa implementuje dwa interfejsy, które mają metodę rozszerzającą o tej samej sygnaturze, żadna z tych metod rozszerzających nie będzie widoczna.

  • Rozszerz najbardziej szczegółowy typ.W hierarchii typów, jeśli wybierzesz typ, z którego pochodzi wiele innych typów, istnieją warstwy możliwości wprowadzenia metod instancji lub innych metod rozszerzających, które mogą kolidować z Twoimi.

Metody rozszerzające, wystąpienia metod i właściwości

Kiedy mieszcząca się w zakresie metoda wystąpień posiada oznaczenie, które jest zgodne z argumentami instrukcji wywołania, metoda wystąpienia jest wybierana jako preferowana ze wszystkich metod rozszerzenia.Metoda instancji ma pierwszeństwo, nawet jeśli metoda rozszerzenia ma lepsze dopasowanie.W poniższym przykładzie ExampleClass zawiera metodę instancji o nazwie ExampleMethod, która ma jeden parametr typu Integer.Metoda rozszerzająca ExampleMethod rozszerza ExampleClass i ma jeden parametr typu 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

Pierwsze wywołanie ExampleMethod w poniższym kodzie wywołuje metodę rozszerzenia, ponieważ arg1 jest Long i jest zgodny tylko z Long parametrem w metodzie rozszerzenia.Drugie wywołanie ExampleMethod posiada argument Integer, arg2 i wywołuje metodę wystąpienia.

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

Teraz odwróć typy danych parametrów w dwóch metodach:

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

Ten czas w kodzie w Main wywołuje w obu przypadkach metodę wystąpienia.Jest tak, ponieważ zarówno arg1 i arg2 mają rozszerzającą się konwersję na Long, i metoda wystąpienia ma pierwszeństwo przez metoda rozszerzenia w obu przypadkach.

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

Tym samym, metoda rozszerzeń nie może zastąpić istniejącej metody wystąpienia.Jednakże gdy metoda rozszerzająca ma taką samą nazwę, jak metoda wystąpienia, a ich podpisy nie będą w konflikcie, obie metody będą dostępne.Na przykład jeśli klasa ExampleClass zawiera metodę o nazwie ExampleMethod, która nie przyjmuje argumentów, dopuszczalne są metody rozszerzające o tej samej nazwie, ale z innym podpisem, tak jak pokazano w poniższym kodzie.

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

Wynik tego kodu jest następujący:

Extension method

Instance method

Ta sytuacja jest prostsza w przypadku właściwości: jeżeli metoda rozszerzenia ma tę samą nazwę jak właściwość klasy, którą rozszerza, metoda rozszerzenia nie jest widoczna i nie ma do niej dostępu.

Pierwszeństwo metody rozszerzającej

Jeżeli dwie metody rozszerzające, posiadające identyczne oznaczenie są z zakresie oraz są dostępne, wywołana zostanie ta z większym pierwszeństwem.Pierwszeństwo metody rozszerzenia opiera się na mechanizmie zastosowanym w celu dostosowania metody do zakresu.Na poniższej liście przedstawiono hierarchię pierwszeństwa, od najwyższego do najniższego.

  1. Metody rozszerzające zdefiniowane wewnątrz bieżącego modułu.

  2. Metody rozszerzające zdefiniowane wewnątrz typów danych w bieżącej przestrzeni nazw lub w jednym z elementów nadrzędnych z podrzędną przestrzenią nazw mającą wyższy priorytet niż nadrzędna przestrzeń nazw.

  3. Metody rozszerzające zdefiniowane wewnątrz dowolnego typu importu w bieżącym pliku.

  4. Metody rozszerzające zdefiniowane wewnątrz dowolnej importowanej przestrzeni nazw w bieżącym pliku.

  5. Metody rozszerzające zdefiniowane wewnątrz dowolnego typu importu na poziomie projektu.

  6. Metody rozszerzające zdefiniowane wewnątrz dowolnej importowanej przestrzeni nazw na poziomie projektu.

Jeśli pierwszeństwo nie rozwiązuje niejasności, można użyć w pełni kwalifikowanej nazwy, aby określić metodę, którą wywołujesz.Jeśli metoda Print w poprzednim przykładzie jest zdefiniowana w module o nazwie StringExtensions, w pełni kwalifikowana nazwa to StringExtensions.Print(example) zamiast example.Print().

Zobacz też

Informacje

System.Runtime.CompilerServices

Metody rozszerzeń (Przewodnik programowania w języku C#)

Module — Instrukcja

Atrybuty (C# i Visual Basic)

ExtensionAttribute

Koncepcje

Parametry i argumenty procedur (Visual Basic)

Parametry opcjonalne (Visual Basic)

Parameter — Tablice (Visual Basic)

Zakres w Visual Basic