Erweiterungsmethoden (Visual Basic)Extension Methods (Visual Basic)

Erweiterungsmethoden ermöglichen Entwicklern das Hinzufügen von benutzerdefinierten Funktionen, Datentypen, die bereits definiert sind, ohne dass einen neuen abgeleiteten Typ erstellt.Extension methods enable developers to add custom functionality to data types that are already defined without creating a new derived type. Erweiterungsmethoden ermöglichen das Schreiben einer Methode, die aufgerufen werden können, als wäre sie eine des vorhandenen Typs Instanzenmethode.Extension methods make it possible to write a method that can be called as if it were an instance method of the existing type.

HinweiseRemarks

Eine Erweiterungsmethode kann ausschließlich eine Sub-Prozedur oder eine Function-Prozedur sein.An extension method can be only a Sub procedure or a Function procedure. Erweiterungseigenschaften, -felder oder -ereignisse können nicht definiert werden.You cannot define an extension property, field, or event. Alle Erweiterungsmethoden müssen mit dem Erweiterungsattribut <Extension()> aus dem System.Runtime.CompilerServices-Namespace markiert werden.All extension methods must be marked with the extension attribute <Extension()> from the System.Runtime.CompilerServices namespace.

Der erste Parameter in der Definition einer Erweiterungsmethode gibt den Datentyp an, der von der Methode erweitert wird.The first parameter in an extension method definition specifies which data type the method extends. Beim Ausführen der Methode wird der erste Parameter an die Instanz des Datentyps gebunden, der die Methode aufruft.When the method is run, the first parameter is bound to the instance of the data type that invokes the method.

BeispielExample

BeschreibungDescription

Im folgenden Beispiel wird eine Print-Erweiterung für den String-Datentyp definiert.The following example defines a Print extension to the String data type. Die Methode verwendet Console.WriteLine, um eine Zeichenfolge anzuzeigen.The method uses Console.WriteLine to display a string. Durch den Print-Parameter der aString-Methode wird festgelegt, dass die String-Klasse von der Methode erweitert wird.The parameter of the Print method, aString, establishes that the method extends the String class.

Imports System.Runtime.CompilerServices

Module StringExtensions

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

End Module

Beachten Sie, dass die Definition der Erweiterungsmethode mit dem Erweiterungsattribut <Extension()> markiert ist.Notice that the extension method definition is marked with the extension attribute <Extension()>. Die Markierung des Moduls, in dem die Methode definiert ist, ist optional, aber jede Erweiterungsmethode muss markiert werden.Marking the module in which the method is defined is optional, but each extension method must be marked. Zum Zugriff auf das Erweiterungsattribut muss System.Runtime.CompilerServices importiert werden.System.Runtime.CompilerServices must be imported in order to access the extension attribute.

Erweiterungsmethoden können nur innerhalb von Modulen deklariert werden.Extension methods can be declared only within modules. Bei dem Modul, in dem eine Erweiterungsmethode definiert wird, handelt es sich normalerweise um ein anderes Modul als das, in dem sie aufgerufen wird.Typically, the module in which an extension method is defined is not the same module as the one in which it is called. Stattdessen wird das Modul, in dem die Erweiterungsmethode enthalten ist, ggf. importiert, um es in den Gültigkeitsbereich einzubinden.Instead, the module that contains the extension method is imported, if it needs to be, to bring it into scope. Nachdem sich das Modul, in dem Print enthalten ist, im Gültigkeitsbereich befindet, kann die Methode wie jede andere gewöhnliche Instanzenmethode, die keine Argumente verwendet (z. B. ToUpper) aufgerufen werden:After the module that contains Print is in scope, the method can be called as if it were an ordinary instance method that takes no arguments, such as 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

Das nächste Beispiel, PrintAndPunctuate, ist auch eine Erweiterung für String und wird dieses Mal mit zwei Parametern definiert.The next example, PrintAndPunctuate, is also an extension to String, this time defined with two parameters. Der erste Parameter, aString, legt fest, dass die Erweiterungsmethode String erweitert.The first parameter, aString, establishes that the extension method extends String. Mit dem zweiten Parameter, punc, wird eine aus Satzzeichen bestehende Zeichenfolge bereitgestellt, die beim Aufruf der Methode als Argument übergeben wird.The second parameter, punc, is intended to be a string of punctuation marks that is passed in as an argument when the method is called. Durch die Methode wird die Zeichenfolge gefolgt von den Satzzeichen angezeigt.The method displays the string followed by the punctuation marks.

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

Die Methode wird aufgerufen, indem ein Zeichenfolgenargument für punc gesendet wird: example.PrintAndPunctuate(".")The method is called by sending in a string argument for punc: example.PrintAndPunctuate(".")

Im folgenden Beispiel werden Print und PrintAndPunctuate definiert und aufgerufen.The following example shows Print and PrintAndPunctuate defined and called. System.Runtime.CompilerServices wird in das Definitionsmodul importiert, um den Zugriff auf das Erweiterungsattribut zu ermöglichen.System.Runtime.CompilerServices is imported in the definition module in order to enable access to the extension attribute.

CodeCode

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  

Als Nächstes werden die Erweiterungsmethoden in den Gültigkeitsbereich eingebunden und aufgerufen.Next, the extension methods are brought into scope and called.

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  

KommentareComments

Die einzige Voraussetzung für das Ausführen dieser oder ähnlicher Erweiterungsmethoden besteht darin, dass sie sich innerhalb des Gültigkeitsbereichs befinden müssen.All that is required to be able to run these or similar extension methods is that they be in scope. Wenn sich das Modul mit einer Erweiterungsmethode im Gültigkeitsbereich befindet, ist es für IntelliSense erkennbar und kann wie jede andere gewöhnliche Instanzenmethode aufgerufen werden.If the module that contains an extension method is in scope, it is visible in IntelliSense and can be called as if it were an ordinary instance method.

Beachten Sie, dass beim Aufrufen der Methoden kein Argument für den ersten Parameter gesendet wird.Notice that when the methods are invoked, no argument is sent in for the first parameter. Der aString-Parameter in den vorherigen Methodendefinitionen ist an example gebunden, also die Instanz von String, durch die sie aufgerufen werden.Parameter aString in the previous method definitions is bound to example, the instance of String that calls them. Der Compiler verwendet example als das an den ersten Parameter gesendete Argument.The compiler will use example as the argument sent to the first parameter.

Wenn eine Erweiterungsmethode für ein Objekt aufgerufen wird, das auf Nothing festgelegt ist, wird die Erweiterungsmethode ausgeführt.If an extension method is called for an object that is set to Nothing, the extension method executes. Dies trifft nicht auf normale Instanzmethoden zu.This does not apply to ordinary instance methods. Sie können in der Erweiterungsmethode explizit auf Nothing überprüfen.You can explicitly check for Nothing in the extension method.

Erweiterungsfähige TypenTypes That Can Be Extended

Erweiterungsmethoden können für die meisten Typen definiert werden, die in Visual Basic-Parameterlisten wie den folgenden dargestellt werden können:You can define an extension method on most types that can be represented in a Visual Basic parameter list, including the following:

  • Klassen (Referenztypen)Classes (reference types)

  • Strukturen (Werttypen)Structures (value types)

  • SchnittstellenInterfaces

  • DelegatenDelegates

  • ByRef- und ByVal-ArgumenteByRef and ByVal arguments

  • Parameter für generische MethodenGeneric method parameters

  • ArraysArrays

Da der erste Parameter den Datentyp angibt, der durch die Erweiterungsmethode erweitert wird, ist er erforderlich und kann nicht ausgelassen werden.Because the first parameter specifies the data type that the extension method extends, it is required and cannot be optional. Aus diesem Grund kann ein Optional-Parameter oder ein ParamArray-Parameter nicht der erste Parameter in der Parameterliste sein.For that reason, Optional parameters and ParamArray parameters cannot be the first parameter in the parameter list.

Erweiterungsmethoden werden bei der späten Bindung nicht berücksichtigt.Extension methods are not considered in late binding. Im folgenden Beispiel löst die anObject.PrintMe()-Anweisung eine MissingMemberException-Ausnahme aus. Dieselbe Ausnahme wird angezeigt, wenn die zweite PrintMe-Erweiterungsmethodendefinition gelöscht würde.In the following example, the statement anObject.PrintMe() raises a MissingMemberException exception, the same exception you would see if the second PrintMe extension method definition were deleted.

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

Bewährte MethodenBest Practices

Erweiterungsmethoden bieten eine einfache und leistungsstarke Möglichkeit zur Erweiterung eines vorhandenen Typs.Extension methods provide a convenient and powerful way to extend an existing type. Um sie erfolgreich zu verwenden, sind jedoch einige Punkte zu beachten.However, to use them successfully, there are some points to consider. Obwohl sich diese Überlegungen hauptsächlich auf Autoren von Klassenbibliotheken beziehen, können sie gleichzeitig Anwendungen betreffen, die Erweiterungsmethoden verwenden.These considerations apply mainly to authors of class libraries, but they might affect any application that uses extension methods.

Erweiterungsmethoden, die Sie Typen hinzufügen, die sich nicht in Ihrem Besitz befinden, sind im Allgemeinen angreifbarer als Erweiterungsmethoden, die Sie Typen hinzufügen, die von Ihnen gesteuert werden.Most generally, extension methods that you add to types that you do not own are more vulnerable than extension methods added to types that you control. In Klassen, die sich nicht in Ihrem Besitz befinden, können einige Ereignisse auftreten, die Ihre Erweiterungsmethoden negativ beeinflussen könnten.A number of things can occur in classes you do not own that can interfere with your extension methods.

  • Falls ein Instanzenmember vorhanden ist, auf den zugegriffen werden kann und der über eine mit den Argumenten in der aufrufenden Anweisung kompatible Signatur verfügt, ohne dass einschränkende Konvertierungen vom Argument zum Parameter festgelegt sind, wird die Instanzenmethode vor allen Erweiterungsmethoden verwendet.If any accessible instance member exists that has a signature that is compatible with the arguments in the calling statement, with no narrowing conversions required from argument to parameter, the instance method will be used in preference to any extension method. Daher ist es möglich, dass auf einen vorhandenen Erweiterungsmember, den Sie verwenden möchten, nicht mehr zugegriffen werden kann, wenn einer Klasse zu einem bestimmten Zeitpunkt eine geeignete Instanzenmethode hinzugefügt wird.Therefore, if an appropriate instance method is added to a class at some point, an existing extension member that you rely on may become inaccessible.

  • Der Autor einer Erweiterungsmethode kann nicht verhindern, dass andere Programmierer Erweiterungsmethoden schreiben, die Vorrang vor der ursprünglichen Erweiterung haben und damit Konflikte verursachen.The author of an extension method cannot prevent other programmers from writing conflicting extension methods that may have precedence over the original extension.

  • Sie können die Stabilität verbessern, indem Sie Erweiterungsmethoden in einen eigenen Namespace einfügen.You can improve robustness by putting extension methods in their own namespace. Consumer Ihrer Bibliothek können einen Namespace dann ein- oder ausschließen bzw. vom Rest der Bibliothek getrennt unter den Namespaces auswählen.Consumers of your library can then include a namespace or exclude it, or select among namespaces, separately from the rest of the library.

  • Das Erweitern von Schnittstellen bietet u. U. mehr Sicherheit als das Erweitern von Klassen, insbesondere, wenn Sie nicht der Besitzer der Schnittstelle oder Klasse sind.It may be safer to extend interfaces than it is to extend classes, especially if you do not own the interface or class. Eine Änderung einer Schnittstelle wirkt sich auf jede Klasse aus, die von ihr implementiert wird.A change in an interface affects every class that implements it. Deshalb ist es eher unwahrscheinlich, dass der Autor Methoden in einer Schnittstelle hinzufügt oder ändert.Therefore, the author may be less likely to add or change methods in an interface. Wenn eine Klasse jedoch zwei Schnittstellen implementiert, die über Erweiterungsmethoden mit gleicher Signatur verfügen, wird keine der Erweiterungsmethoden angezeigt.However, if a class implements two interfaces that have extension methods with the same signature, neither extension method is visible.

  • Erweitern Sie einen möglichst spezifischen Typ.Extend the most specific type you can. Wenn Sie in einer Typhierarchie einen Typ auswählen, von dem viele andere Typen abgeleitet sind, können auf viele Weisen Instanzenmethoden oder andere Erweiterungsmethoden eingeführt werden, die Konflikte mit Ihren Instanzen- oder Erweiterungsmethoden verursachen könnten.In a hierarchy of types, if you select a type from which many other types are derived, there are layers of possibilities for the introduction of instance methods or other extension methods that might interfere with yours.

Erweiterungsmethoden, Instanzmethoden und EigenschaftenExtension Methods, Instance Methods, and Properties

Wenn eine Instanzmethode im Gültigkeitsbereich über eine Signatur verfügt, die mit den Argumenten einer Aufrufanweisung kompatibel ist, wird die Instanzmethode vor den Erweiterungsmethoden bevorzugt ausgewählt.When an in-scope instance method has a signature that is compatible with the arguments of a calling statement, the instance method is chosen in preference to any extension method. Die Instanzmethode hat auch dann Vorrang, wenn die Erweiterungsmethode eine bessere Übereinstimmung aufweist.The instance method has precedence even if the extension method is a better match. Im folgenden Beispiel enthält die ExampleClass eine Instanzmethode mit der Bezeichnung ExampleMethod, die über einen Parameter des Typs Integer verfügt.In the following example, ExampleClass contains an instance method named ExampleMethod that has one parameter of type Integer. Die Erweiterungsmethode ExampleMethod erweitert die ExampleClass und verfügt über einen Parameter des Typs Long.Extension method ExampleMethod extends ExampleClass, and has one parameter of type 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

Mit dem ersten Aufruf an ExampleMethod im folgenden Code wird die Erweiterungsmethode aufgerufen, da arg1 den Wert Long hat und nur mit dem Long-Parameter in der Erweiterungsmethode kompatibel ist.The first call to ExampleMethod in the following code calls the extension method, because arg1 is Long and is compatible only with the Long parameter in the extension method. Der zweite Aufruf von ExampleMethod verfügt über ein Integer-Argument, arg2, und es ruft die Instanzmethode auf.The second call to ExampleMethod has an Integer argument, arg2, and it calls the instance method.

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

Kehren Sie nun die Datentypen der Parameter in den zwei Methoden um:Now reverse the data types of the parameters in the two methods:

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

Dieses Mal ruft der Code in Main beide Male die Instanzmethode auf.This time the code in Main calls the instance method both times. Das liegt daran, dass sowohl arg1 und arg2 über eine Erweiterungskonvertierung zu Long verfügen, und die Instanzmethode in beiden Fällen Vorrang vor der Erweiterungsmethode hat.This is because both arg1 and arg2 have a widening conversion to Long, and the instance method takes precedence over the extension method in both cases.

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

Dies bedeutet, dass eine Erweiterungsmethode keine vorhandene Instanzmethode ersetzen kann.Therefore, an extension method cannot replace an existing instance method. Wenn eine Erweiterungsmethode jedoch über denselben Namen wie eine Instanzmethode verfügt, die Signaturen aber keine Konflikte verursachen, kann auf beide Methoden zugegriffen werden.However, when an extension method has the same name as an instance method but the signatures do not conflict, both methods can be accessed. Wenn die ExampleClass beispielsweise eine Methode mit dem Namen ExampleMethod enthält, die keine Argumente verwendet, sind Erweiterungsmethoden mit demselben Namen aber unterschiedlichen Signaturen zulässig, wie in folgendem Code dargestellt.For example, if class ExampleClass contains a method named ExampleMethod that takes no arguments, extension methods with the same name but different signatures are permitted, as shown in the following code.

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

Dieser Code generiert folgende Ausgabe:The output from this code is as follows:

Extension method

Instance method

Bezüglich Eigenschaften ist der Sachverhalt unkomplizierter: Wenn eine Erweiterungsmethode den gleichen Namen wie eine Eigenschaft der Klasse hat, die sie erweitert, wird die Erweiterungsmethode nicht angezeigt, und es kann nicht darauf zugegriffen werden.The situation is simpler with properties: if an extension method has the same name as a property of the class it extends, the extension method is not visible and cannot be accessed.

Rangfolge von ErweiterungsmethodenExtension Method Precedence

Wenn sich zwei Erweiterungsmethoden mit identischen Signaturen im Gültigkeitsbereich befinden und zugreifbar sind, wird die Methode mit der höheren Rangfolge aufgerufen.When two extension methods that have identical signatures are in scope and accessible, the one with higher precedence will be invoked. Die Rangfolge einer Erweiterungsmethode basiert auf dem Mechanismus, der verwendet wird, um die Methode in den Gültigkeitsbereich einzubinden.An extension method's precedence is based on the mechanism used to bring the method into scope. Die folgende Liste gibt die hierarchische Rangfolge von oben nach unten an:The following list shows the precedence hierarchy, from highest to lowest.

  1. Im aktuellen Modul definierte Erweiterungsmethoden.Extension methods defined inside the current module.

  2. Erweiterungsmethoden, die innerhalb von Datentypen im aktuellen Namespace oder in übergeordneten Namespaces definiert sind, wobei untergeordnete Namespaces eine höhere Rangfolge als übergeordnete Namespaces haben.Extension methods defined inside data types in the current namespace or any one of its parents, with child namespaces having higher precedence than parent namespaces.

  3. In Typimporten in der aktuellen Datei definierte Erweiterungsmethoden.Extension methods defined inside any type imports in the current file.

  4. In Namespaceimporten in der aktuellen Datei definierte Erweiterungsmethoden.Extension methods defined inside any namespace imports in the current file.

  5. In Typimporten auf Projektebene definierte Erweiterungsmethoden.Extension methods defined inside any project-level type imports.

  6. In Namespaceimporten auf Projektebene definierte Erweiterungsmethoden.Extension methods defined inside any project-level namespace imports.

Wenn sich die Mehrdeutigkeit durch die Anwendung einer Rangfolge nicht auflösen lässt, können Sie den vollqualifizierten Namen zum Festlegen der aufgerufenen Methode verwenden.If precedence does not resolve the ambiguity, you can use the fully qualified name to specify the method that you are calling. Wenn die Print-Methode aus dem vorherigen Beispiel in einem Modul mit dem Namen StringExtensions definiert wird, lautet der vollqualifizierte Name StringExtensions.Print(example) und nicht example.Print().If the Print method in the earlier example is defined in a module named StringExtensions, the fully qualified name is StringExtensions.Print(example) instead of example.Print().

Siehe auchSee Also

System.Runtime.CompilerServices
ExtensionAttribute
ErweiterungsmethodenExtension Methods
Module-AnweisungModule Statement
Parameter und Argumente von ProzedurenProcedure Parameters and Arguments
Optionale ParameterOptional Parameters
ParameterarraysParameter Arrays
Übersicht über AttributeAttributes overview
Gültigkeitsbereich in Visual BasicScope in Visual Basic