Metodi di estensione (Visual Basic)Extension Methods (Visual Basic)

I metodi di estensione consentono agli sviluppatori di aggiungere funzionalità personalizzate ai tipi di dati che sono già definiti senza creare un nuovo tipo derivato.Extension methods enable developers to add custom functionality to data types that are already defined without creating a new derived type. I metodi di estensione consentono di scrivere un metodo che può essere chiamato come se fosse un metodo di istanza del tipo esistente.Extension methods make it possible to write a method that can be called as if it were an instance method of the existing type.

NoteRemarks

Un metodo di estensione può essere solo un Sub routine o un Function procedure.An extension method can be only a Sub procedure or a Function procedure. È possibile definire una proprietà di estensione, un campo o un evento.You cannot define an extension property, field, or event. Tutti i metodi di estensione devono essere contrassegnati con l'attributo di estensione <Extension()> dal System.Runtime.CompilerServices dello spazio dei nomi.All extension methods must be marked with the extension attribute <Extension()> from the System.Runtime.CompilerServices namespace.

Il primo parametro in una definizione di metodo di estensione specifica quale tipo di dati esteso dal metodo.The first parameter in an extension method definition specifies which data type the method extends. Quando il metodo viene eseguito, il primo parametro è associato all'istanza del tipo di dati che richiama il metodo.When the method is run, the first parameter is bound to the instance of the data type that invokes the method.

EsempioExample

DescrizioneDescription

L'esempio seguente definisce una Print estensione per il String tipo di dati.The following example defines a Print extension to the String data type. Il metodo Usa Console.WriteLine per visualizzare una stringa.The method uses Console.WriteLine to display a string. Il parametro del Print metodo aString, stabilisce che il metodo estende il String classe.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

Si noti che la definizione di metodo di estensione è contrassegnata con l'attributo di estensione <Extension()>.Notice that the extension method definition is marked with the extension attribute <Extension()>. Il contrassegno del modulo in cui è definito il metodo è facoltativo, ma ogni metodo di estensione deve essere contrassegnato.Marking the module in which the method is defined is optional, but each extension method must be marked. System.Runtime.CompilerServices deve essere importato per accedere all'attributo di estensione.System.Runtime.CompilerServices must be imported in order to access the extension attribute.

I metodi di estensione possono essere dichiarati solo all'interno dei moduli.Extension methods can be declared only within modules. Il modulo in cui è definito un metodo di estensione non è in genere, il modulo stesso di quello in cui viene chiamato.Typically, the module in which an extension method is defined is not the same module as the one in which it is called. Al contrario, viene importato il modulo che contiene il metodo di estensione, se deve essere, per portarlo nell'ambito.Instead, the module that contains the extension method is imported, if it needs to be, to bring it into scope. Dopo il modulo che contiene Print è incluso nell'ambito, il metodo può essere chiamato come se fosse un metodo di istanza comune che non accetta argomenti, ad esempio ToUpper: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

L'esempio successivo PrintAndPunctuate, è anche un'estensione String, questa volta definito con due parametri.The next example, PrintAndPunctuate, is also an extension to String, this time defined with two parameters. Il primo parametro, aString, stabilisce che il metodo di estensione estende String.The first parameter, aString, establishes that the extension method extends String. Il secondo parametro, punc, deve essere una stringa di segni di punteggiatura che viene passata come argomento quando viene chiamato il metodo.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. Il metodo visualizza la stringa seguita dai segni di punteggiatura.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

Il metodo viene chiamato inviando un argomento stringa per punc: example.PrintAndPunctuate(".")The method is called by sending in a string argument for punc: example.PrintAndPunctuate(".")

L'esempio seguente illustra Print e PrintAndPunctuate definizione e la chiamata.The following example shows Print and PrintAndPunctuate defined and called. System.Runtime.CompilerServices viene importato nel modulo della definizione per consentire l'accesso all'attributo di estensione.System.Runtime.CompilerServices is imported in the definition module in order to enable access to the extension attribute.

CodiceCode

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  

Successivamente, i metodi di estensione vengono inseriti nell'ambito e chiamati.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  

CommentiComments

Tutto ciò che è necessario essere in grado di eseguire questi passaggi o metodi di estensione simili è che si trovino nell'ambito.All that is required to be able to run these or similar extension methods is that they be in scope. Se il modulo che contiene un metodo di estensione è nell'ambito, è visibile in IntelliSense e può essere chiamato come se fosse un metodo di istanza ordinari.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.

Si noti che quando vengono richiamati i metodi, viene inviato alcun argomento per il primo parametro.Notice that when the methods are invoked, no argument is sent in for the first parameter. Parametro aString nel precedente metodo definizioni è associato a example, l'istanza di String che li chiama.Parameter aString in the previous method definitions is bound to example, the instance of String that calls them. Il compilatore userà example come argomento inviato al primo parametro.The compiler will use example as the argument sent to the first parameter.

Se viene chiamato un metodo di estensione per un oggetto che è impostato su Nothing, viene eseguito il metodo di estensione.If an extension method is called for an object that is set to Nothing, the extension method executes. Ciò non si applica ai metodi di istanza comune.This does not apply to ordinary instance methods. È possibile controllare in modo esplicito per Nothing nel metodo di estensione.You can explicitly check for Nothing in the extension method.

Tipi che possono essere esteseTypes That Can Be Extended

È possibile definire un metodo di estensione nella maggior parte dei tipi che possono essere rappresentati in un elenco di parametri di Visual Basic, inclusi i seguenti:You can define an extension method on most types that can be represented in a Visual Basic parameter list, including the following:

  • Classi (tipi riferimento)Classes (reference types)

  • Strutture (tipi di valore)Structures (value types)

  • InterfacceInterfaces

  • DelegatiDelegates

  • Argomenti ByRef e ByValByRef and ByVal arguments

  • Parametri di metodo genericoGeneric method parameters

  • MatriciArrays

Poiché il primo parametro specifica il tipo di dati esteso dal metodo di estensione, è obbligatorio e non può essere facoltativo.Because the first parameter specifies the data type that the extension method extends, it is required and cannot be optional. Per questo motivo Optional parametri e ParamArray parametri non possono essere il primo parametro nell'elenco dei parametri.For that reason, Optional parameters and ParamArray parameters cannot be the first parameter in the parameter list.

I metodi di estensione non sono considerati nell'associazione tardiva.Extension methods are not considered in late binding. Nell'esempio seguente, l'istruzione anObject.PrintMe() genera una MissingMemberException eccezione, la stessa eccezione sarebbe visualizzata se il secondo PrintMe definizione di metodo di estensione sono stati eliminati.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

SuggerimentiBest Practices

I metodi di estensione forniscono un modo pratico e potente per estendere un tipo esistente.Extension methods provide a convenient and powerful way to extend an existing type. Tuttavia, per poterli utilizzare correttamente, esistono alcuni aspetti da considerare.However, to use them successfully, there are some points to consider. Queste considerazioni si applicano principalmente gli autori delle librerie di classi, ma che potrebbero influire su qualsiasi applicazione che usa i metodi di estensione.These considerations apply mainly to authors of class libraries, but they might affect any application that uses extension methods.

In generale, i metodi di estensione aggiunti ai tipi che non si possiede sono più vulnerabili dei metodi di estensione aggiunti ai tipi di cui si controllano.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. Può verificarsi una serie di operazioni nelle classi non si è proprietari che possono interferire con i metodi di estensione.A number of things can occur in classes you do not own that can interfere with your extension methods.

  • Se è presente alcun membro di istanza accessibile ha una firma compatibile con gli argomenti dell'istruzione chiamante, con nessuna conversione narrowing richiesto dall'argomento al parametro, verrà utilizzato il metodo di istanza preferenza rispetto a qualsiasi metodo di estensione.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. Pertanto, se un metodo di istanza appropriato viene aggiunto a una classe a un certo punto, un membro di estensione esistente che affidano potrebbe diventare inaccessibile.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.

  • L'autore di un metodo di estensione non è possibile impedire agli altri programmatori di scrivere metodi di estensione in conflitto che possono avere la precedenza sull'estensione originale.The author of an extension method cannot prevent other programmers from writing conflicting extension methods that may have precedence over the original extension.

  • È possibile migliorare la robustezza inserendo i metodi di estensione nel rispettivo spazio dei nomi.You can improve robustness by putting extension methods in their own namespace. La libreria può quindi includere uno spazio dei nomi o escluderlo oppure effettuare una selezione tra gli spazi dei nomi, separatamente dal resto della libreria.Consumers of your library can then include a namespace or exclude it, or select among namespaces, separately from the rest of the library.

  • Potrebbe essere più sicuro estendere le interfacce di cui è possibile estendere le classi, soprattutto se non si possiede l'interfaccia o classe.It may be safer to extend interfaces than it is to extend classes, especially if you do not own the interface or class. Una modifica in un'interfaccia influisce su ogni classe che lo implementa.A change in an interface affects every class that implements it. Pertanto, l'autore potrebbe essere meno probabile che aggiungere o modificare i metodi in un'interfaccia.Therefore, the author may be less likely to add or change methods in an interface. Tuttavia, se una classe implementa due interfacce con metodi di estensione con la stessa firma, nessuno dei due metodi di estensione sono visibili.However, if a class implements two interfaces that have extension methods with the same signature, neither extension method is visible.

  • Estendere il tipo più specifico, che è possibile.Extend the most specific type you can. In una gerarchia di tipi, se si seleziona un tipo dal quale sono derivati molti altri tipi, sono presenti livelli di possibilità per l'introduzione di metodi di istanza o altri metodi di estensione che potrebbero interferire con i propri.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.

I metodi di estensione, metodi di istanza e proprietàExtension Methods, Instance Methods, and Properties

Quando un metodo di istanza inclusi nell'ambito ha una firma compatibile con gli argomenti di un'istruzione di chiamata, il metodo di istanza viene preferito a qualsiasi metodo di estensione.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. Il metodo di istanza ha la precedenza anche se il metodo di estensione è una corrispondenza migliore.The instance method has precedence even if the extension method is a better match. Nell'esempio riportato di seguito ExampleClass contiene un metodo di istanza denominato ExampleMethod che ha un parametro di tipo Integer.In the following example, ExampleClass contains an instance method named ExampleMethod that has one parameter of type Integer. Metodo di estensione ExampleMethod estende ExampleClass, e ha un parametro di tipo 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

La prima chiamata a ExampleMethod nel codice seguente chiama il metodo di estensione, in quanto arg1 viene Long ed è compatibile solo con il Long parametro nel metodo di estensione.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. La seconda chiamata a ExampleMethod ha un Integer argomento, arg2, e chiama il metodo di istanza.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

Invertire ora i tipi di dati dei parametri nei due metodi: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

Questa volta il codice in Main chiama il metodo di istanza due volte.This time the code in Main calls the instance method both times. Infatti, entrambi arg1 e arg2 hanno una conversione widening Long, e il metodo di istanza ha la precedenza sul metodo di estensione in entrambi i casi.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

Pertanto, un metodo di estensione non è possibile sostituire un metodo di istanza esistenti.Therefore, an extension method cannot replace an existing instance method. Tuttavia, quando un metodo di estensione ha lo stesso nome di un metodo di istanza ma le firme non sono in conflitto, entrambi i metodi accessibili.However, when an extension method has the same name as an instance method but the signatures do not conflict, both methods can be accessed. Ad esempio, se classe ExampleClass contiene un metodo denominato ExampleMethod che non accetta argomenti, i metodi di estensione con lo stesso nome ma sono consentite firme diverse, come illustrato nel codice seguente.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

Come indicato di seguito è riportato l'output da questo codice:The output from this code is as follows:

Extension method

Instance method

La situazione è più semplice con proprietà: se un metodo di estensione ha lo stesso nome come una proprietà di classe che estende, il metodo di estensione non è visibile e non è accessibile.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.

Precedenza nei metodi di estensioneExtension Method Precedence

Quando due metodi di estensione che hanno firme identiche sono nell'ambito e accessibili, verrà richiamato quello con priorità più alta.When two extension methods that have identical signatures are in scope and accessible, the one with higher precedence will be invoked. Precedenza di un metodo di estensione è basata sul meccanismo utilizzato per portare il metodo nell'ambito.An extension method's precedence is based on the mechanism used to bring the method into scope. Nell'elenco seguente mostra la gerarchia di precedenza, dal maggiore al minore.The following list shows the precedence hierarchy, from highest to lowest.

  1. Metodi di estensione definiti all'interno del modulo corrente.Extension methods defined inside the current module.

  2. Metodi di estensione definiti all'interno di dati tipi nella spazio dei nomi corrente o uno qualsiasi dei relativi elementi padre, gli spazi dei nomi figlio con precedenza maggiore rispetto a spazi dei nomi padre.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. Metodi di estensione definiti in qualsiasi importazione di tipo nel file corrente.Extension methods defined inside any type imports in the current file.

  4. Metodi di estensione definiti in qualsiasi importazione dello spazio dei nomi nel file corrente.Extension methods defined inside any namespace imports in the current file.

  5. Metodi di estensione definiti in qualsiasi importazione di tipi a livello di progetto.Extension methods defined inside any project-level type imports.

  6. Metodi di estensione definiti in qualsiasi importazione dello spazio dei nomi a livello di progetto.Extension methods defined inside any project-level namespace imports.

Se la precedenza non risolve l'ambiguità, è possibile usare il nome completo per specificare il metodo che si sta chiamando.If precedence does not resolve the ambiguity, you can use the fully qualified name to specify the method that you are calling. Se il Print metodo nell'esempio precedente viene definito in un modulo denominato StringExtensions, specificare il nome completo viene StringExtensions.Print(example) invece di 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().

Vedere ancheSee also