Metodi di estensione (Visual Basic)
I metodi di estensione consentono agli sviluppatori di aggiungere funzionalità personalizzate ai tipi di dati già definiti senza creare un nuovo tipo derivato. I metodi di estensione consentono di scrivere un metodo che può essere chiamato come se fosse un metodo di istanza del tipo esistente.
Commenti
Un metodo di estensione può essere solo una routine o una Sub
Function
routine. Non è possibile definire una proprietà di estensione, un campo o un evento. Tutti i metodi di estensione devono essere contrassegnati con l'attributo <Extension>
System.Runtime.CompilerServices di estensione dallo spazio dei nomi e devono essere definiti in un modulo. Se un metodo di estensione viene definito all'esterno di un modulo, il compilatore Visual Basic genera l'errore BC36551, "I metodi di estensione possono essere definiti solo nei moduli".
Il primo parametro in una definizione del metodo di estensione specifica il tipo di dati esteso dal metodo. Quando viene eseguito il metodo, il primo parametro è associato all'istanza del tipo di dati che richiama il metodo.
L'attributo Extension
può essere applicato solo a un oggetto Visual Basic Module
, Sub
o Function
. Se lo si applica a o a Class
Structure
, il compilatore Visual Basic genera l'errore BC36550, l'attributo "'Extension" può essere applicato solo alle dichiarazioni 'Module', 'Sub'o 'Function'.
Esempio
Nell'esempio seguente viene definita un'estensione Print
al String tipo di dati. Il metodo usa Console.WriteLine
per visualizzare una stringa. Il parametro del Print
metodo , aString
, stabilisce che il metodo estende la String classe.
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 del metodo di estensione è contrassegnata con l'attributo <Extension()>
di estensione . Contrassegnare il modulo in cui è definito il metodo è facoltativo, ma ogni metodo di estensione deve essere contrassegnato. System.Runtime.CompilerServices deve essere importato per accedere all'attributo di estensione.
I metodi di estensione possono essere dichiarati solo all'interno dei moduli. In genere, il modulo in cui viene definito un metodo di estensione non è lo stesso modulo in cui viene chiamato. Il modulo che contiene il metodo di estensione viene invece importato, se necessario, per inserirlo nell'ambito. Dopo che il modulo che contiene Print
è nell'ambito, il metodo può essere chiamato come se fosse un metodo di istanza normale che non accetta argomenti, ad esempio 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 a String, questa volta definita con due parametri. Il primo parametro, , aString
stabilisce che il metodo di estensione estende String. Il secondo parametro, punc
, è destinato a essere una stringa di segni di punteggiatura passati come argomento quando viene chiamato il metodo. Il metodo visualizza la stringa seguita dai segni di punteggiatura.
<Extension()>
Public Sub PrintAndPunctuate(ByVal aString As String,
ByVal punc As String)
Console.WriteLine(aString & punc)
End Sub
Il metodo viene chiamato inviando in un argomento stringa per punc
: example.PrintAndPunctuate(".")
L'esempio seguente mostra Print
e definito e PrintAndPunctuate
chiamato. System.Runtime.CompilerServices viene importato nel modulo di definizione per abilitare l'accesso all'attributo di estensione.
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
Successivamente, i metodi di estensione vengono inseriti nell'ambito e chiamati:
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
Tutto ciò che è necessario per poter eseguire questi metodi di estensione o simili è che sono nell'ambito. 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 normale.
Si noti che quando vengono richiamati i metodi, non viene inviato alcun argomento per il primo parametro. Il parametro aString
nelle definizioni di metodo precedenti è associato a example
, l'istanza di String
che li chiama. Il compilatore userà example
come argomento inviato al primo parametro.
Se viene chiamato un metodo di estensione per un oggetto impostato su Nothing
, il metodo di estensione viene eseguito. Questa operazione non si applica ai metodi di istanza normali. È possibile verificare Nothing
in modo esplicito nel metodo di estensione.
Tipi che possono essere estesi
È possibile definire un metodo di estensione per la maggior parte dei tipi che possono essere rappresentati in un elenco di parametri di Visual Basic, incluso quanto segue:
- Classi (tipi di riferimento)
- Strutture (tipi di valore)
- Interfacce
- Delegati
- Argomenti ByRef e ByVal
- Parametri del metodo generico
- Matrici
Poiché il primo parametro specifica il tipo di dati esteso dal metodo di estensione, è necessario e non può essere facoltativo. Per questo motivo, Optional
i parametri e ParamArray
i parametri non possono essere il primo parametro nell'elenco dei parametri.
I metodi di estensione non vengono considerati in associazione tardiva. Nell'esempio seguente l'istruzione anObject.PrintMe()
genera un'eccezione MissingMemberException , la stessa eccezione viene visualizzata se la seconda PrintMe
definizione del metodo di estensione è stata eliminata.
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
Procedure consigliate
I metodi di estensione offrono un modo pratico e potente per estendere un tipo esistente. Tuttavia, per usarli correttamente, ci sono alcuni punti da considerare. Queste considerazioni si applicano principalmente agli autori di librerie di classi, ma potrebbero influire su qualsiasi applicazione che usa metodi di estensione.
In genere, i metodi di estensione aggiunti ai tipi che non sono proprietari sono più vulnerabili rispetto ai metodi di estensione aggiunti ai tipi che si controllano. Un numero di cose può verificarsi nelle classi che non è proprietario che può interferire con i metodi di estensione.
Se esiste un membro di istanza accessibile con una firma compatibile con gli argomenti nell'istruzione chiamante, senza alcuna conversione limitata richiesta dall'argomento al parametro, il metodo di istanza verrà usato in preferenza per qualsiasi metodo di estensione. Pertanto, se un metodo di istanza appropriato viene aggiunto a una classe a un certo punto, un membro di estensione esistente a cui si fa affidamento potrebbe diventare inaccessibile.
L'autore di un metodo di estensione non può impedire ad altri programmatori di scrivere metodi di estensione in conflitto che potrebbero avere la precedenza sull'estensione originale.
È possibile migliorare la robustezza inserendo metodi di estensione nel proprio spazio dei nomi. I consumer della libreria possono quindi includere uno spazio dei nomi o escluderlo oppure selezionarlo tra spazi dei nomi, separatamente dal resto della libreria.
Può essere più sicuro estendere le interfacce che per estendere le classi, soprattutto se non si possiede l'interfaccia o la classe. Una modifica in un'interfaccia influisce su ogni classe che lo implementa. Pertanto, l'autore potrebbe essere meno probabile aggiungere o modificare i metodi in un'interfaccia. Tuttavia, se una classe implementa due interfacce con metodi di estensione con la stessa firma, nessuno dei due metodi di estensione è visibile.
Estendere il tipo più specifico che è possibile. In una gerarchia di tipi, se si seleziona un tipo da cui derivano molti altri tipi, esistono livelli di possibilità per l'introduzione di metodi di istanza o altri metodi di estensione che potrebbero interferire con i propri.
Metodi di estensione, metodi di istanza e proprietà
Quando un metodo di istanza nell'ambito ha una firma compatibile con gli argomenti di un'istruzione chiamante, il metodo di istanza viene scelto in preferenza per qualsiasi metodo di estensione. Il metodo di istanza ha la precedenza anche se il metodo di estensione è una corrispondenza migliore. Nell'esempio seguente contiene ExampleClass
un metodo di istanza denominato ExampleMethod
con un parametro di tipo Integer
. Il metodo ExampleMethod
di estensione estende ExampleClass
e ha un parametro di tipo 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, perché arg1
è ed è Long
compatibile solo con il Long
parametro nel metodo di estensione. La seconda chiamata a ExampleMethod
ha un Integer
argomento, arg2
e chiama il metodo di istanza.
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:
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 entrambe le volte. Ciò avviene perché entrambi arg1
e arg2
hanno una conversione più ampia in Long
e il metodo di istanza ha la precedenza sul metodo di estensione in entrambi i casi.
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 può sostituire un metodo di istanza esistente. 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 possono essere accessibili. Ad esempio, se la 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.
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
L'output di questo codice è il seguente:
Extension method
Instance method
La situazione è più semplice con le proprietà: se un metodo di estensione ha lo stesso nome di una proprietà della classe estesa, il metodo di estensione non è visibile e non può essere accessibile.
Precedenza del metodo di estensione
Quando due metodi di estensione con firme identiche sono nell'ambito e accessibili, verrà richiamato quello con precedenza superiore. La precedenza di un metodo di estensione è basata sul meccanismo usato per portare il metodo nell'ambito. L'elenco seguente mostra la gerarchia di precedenza, dal più alto al più basso.
Metodi di estensione definiti all'interno del modulo corrente.
I metodi di estensione definiti all'interno dei tipi di dati nello spazio dei nomi corrente o uno dei relativi genitori, con spazi dei nomi figlio con precedenza superiore rispetto agli spazi dei nomi padre.
I metodi di estensione definiti all'interno di qualsiasi tipo importano nel file corrente.
Metodi di estensione definiti all'interno di qualsiasi importazione dello spazio dei nomi nel file corrente.
Metodi di estensione definiti all'interno di qualsiasi importazione di tipi a livello di progetto.
Metodi di estensione definiti all'interno di qualsiasi importazione dello spazio dei nomi a livello di progetto.
Se la precedenza non risolve l'ambiguità, è possibile usare il nome completo per specificare il metodo che si sta chiamando. Se il metodo nell'esempio precedente è definito in un modulo denominato StringExtensions
, il Print
nome completo è StringExtensions.Print(example)
anziché example.Print()
.
Vedi anche
Commenti e suggerimenti
Invia e visualizza il feedback per