Tipi generici in Visual Basic (Visual Basic)
Un tipo generico è un singolo elemento di programmazione che si adatta per eseguire la stessa funzionalità per più tipi di dati. Quando si definisce una classe o una routine generica, non è necessario definire una versione separata per ogni tipo di dati per cui si vuole eseguire tale funzionalità.
Un'analogia è un set di cacciaviti con teste rimovibili. Ispezioni la vite e selezioni l'inserto corretto per quella vite (a taglio, a croce, a stella). Dopo aver inserito la testa corretta nella maniglia del cacciavite, si esegue la stessa funzione con il cacciavite, vale a dire girando la vite.
Quando si definisce un tipo generico, è necessario parametrizzarlo con uno o più tipi di dati. I parametri di tipo consentono al codice di adattare i tipi di dati ai requisiti. Il codice può dichiarare diversi elementi di programmazione dall'elemento generico, ognuno dei quali agisce su un set diverso di tipi di dati. Tuttavia, tutti gli elementi dichiarati eseguono la logica identica, indipendentemente dai tipi di dati in uso.
Ad esempio, è possibile creare e usare una classe queue che opera su un tipo di dati specifico, ad esempio String
. È possibile dichiarare tale classe da System.Collections.Generic.Queue<T>, come illustrato nell'esempio seguente.
Public stringQ As New System.Collections.Generic.Queue(Of String)
È ora possibile usare stringQ
per lavorare esclusivamente con valori di String
. Poiché stringQ
è specifico per String
invece di essere generalizzato per i valori Object
, non si dispone di binding o conversione di tipi tardivi. I tipi generici consentono di risparmiare tempo di esecuzione e ridurre gli errori di runtime.
Per altre informazioni sull'uso di un tipo generico, vedere Procedura: Usare una classe generica.
Esempio di una classe generica
Nell'esempio seguente viene illustrata una definizione di struttura di una classe generica.
Public Class classHolder(Of t)
Public Sub processNewItem(ByVal newItem As t)
Dim tempItem As t
' Insert code that processes an item of data type t.
End Sub
End Class
Nella struttura precedente, t
è un parametro di tipo , ovvero un segnaposto per un tipo di dati fornito quando si dichiara la classe . Altrove nel codice, è possibile dichiarare diverse versioni di classHolder
fornendo vari tipi di dati per t
. Nell'esempio seguente vengono illustrate due dichiarazioni di questo tipo.
Public integerClass As New classHolder(Of Integer)
Friend stringClass As New classHolder(Of String)
Le istruzioni precedenti dichiarano classi costruite, in cui un tipo specifico sostituisce il parametro di tipo. Questa sostituzione viene propagata in tutto il codice all'interno della classe costruita. Nell'esempio seguente viene mostrato l'aspetto della procedura processNewItem
in integerClass
.
Public Sub processNewItem(ByVal newItem As Integer)
Dim tempItem As Integer
' Inserted code now processes an Integer item.
End Sub
Per un esempio più completo, vedere Procedura: Definire una classe in grado di fornire funzionalità identiche in tipi di dati diversi.
Elementi di programmazione idonei
È possibile definire e usare classi generiche, strutture, interfacce, procedure e delegati. .NET definisce diverse classi, strutture e interfacce generiche che rappresentano elementi generici di uso comune. Lo spazio dei nomi System.Collections.Generic fornisce dizionari, liste, code e stack. Prima di definire il proprio elemento generico, verificare se è già disponibile in System.Collections.Generic.
Le procedure non sono tipi, ma è possibile definire e usare procedure generiche. Vedere procedure generiche in Visual Basic.
Vantaggi dei tipi generici
Un tipo generico funge da base per dichiarare diversi elementi di programmazione, ognuno dei quali opera su un tipo di dati specifico. Le alternative a un tipo generico sono:
- Un singolo tipo che opera sul tipo di dati
Object
. - Un insieme di versioni di tipo specifiche del tipo. Ogni versione viene codificata singolarmente e opera su un tipo di dati specifico, ad esempio
String
,Integer
o un tipo definito dall'utente, ad esempiocustomer
.
Un tipo generico presenta i vantaggi seguenti rispetto a queste alternative:
- Sicurezza dei tipi I tipi generici applicano il controllo dei tipi in fase di compilazione. I tipi basati su
Object
accettano qualsiasi tipo di dati ed è necessario scrivere codice per verificare se un tipo di dati di input è accettabile. Con i tipi generici, il compilatore può intercettare le mancate corrispondenze dei tipi prima del runtime. - Prestazione. I tipi generici non devono casella e dati unbox, perché ognuno è specializzato per un tipo di dati. Le operazioni basate su
Object
devono incapsulare i tipi di dati di input per convertirli inObject
e rimuovere l'incapsulamento dei dati destinati all'output. Boxing e unboxing riducono le prestazioni. Anche i tipi basati suObject
sono legati dinamicamente, il che significa che l'accesso ai membri richiede codice supplementare in fase di esecuzione. Le conversioni dei tipi riducono anche le prestazioni. - Consolidamento del codice. Il codice in un tipo generico deve essere definito una sola volta. Un insieme di versioni specifiche di un tipo deve replicare lo stesso codice in ogni versione, con l'unica differenza essendo il tipo di dati specifico per quella versione. Con i tipi generici, le versioni specifiche del tipo vengono tutte generate dal tipo generico originale.
- Riutilizzo del codice. Il codice che non dipende da un tipo di dati specifico può essere riutilizzato con vari tipi di dati se è generico. Spesso è possibile riutilizzarla anche con un tipo di dati che non è stato previsto in origine.
- Supporto dell'IDE. Quando si usa un tipo costruito dichiarato da un tipo generico, l'ambiente di sviluppo integrato (IDE) può offrire più supporto durante lo sviluppo del codice. Ad esempio, IntelliSense può mostrare le opzioni specifiche del tipo per un argomento a un costruttore o a un metodo.
- Algoritmi generici. Gli algoritmi astratti indipendenti dal tipo sono candidati validi per i tipi generici. Ad esempio, una routine generica che ordina gli elementi usando l'interfaccia IComparable può essere usata con qualsiasi tipo di dati che implementa IComparable.
Vincoli
Anche se il codice in una definizione di tipo generico deve essere il più possibile indipendente dal tipo, potrebbe essere necessario richiedere una determinata funzionalità di qualsiasi tipo di dati fornito al tipo generico. Ad esempio, se si desidera confrontare due elementi per ordinare o collazionare, i loro tipi di dati devono implementare l'interfaccia IComparable. È possibile applicare questo requisito aggiungendo un vincolo al parametro di tipo.
Esempio di vincolo
Nell'esempio seguente viene illustrata una definizione scheletra di una classe con un vincolo che richiede l'argomento di tipo per implementare IComparable.
Public Class itemManager(Of t As IComparable)
' Insert code that defines class members.
End Class
Se il codice successivo tenta di costruire una classe da itemManager
fornendo un tipo che non implementa IComparable, il compilatore segnala un errore.
Tipi di vincoli
Il vincolo può specificare i requisiti seguenti in qualsiasi combinazione:
- L'argomento tipo deve implementare una o più interfacce
- L'argomento di tipo deve essere di tipo o ereditare da, al massimo una classe
- L'argomento type deve esporre un costruttore senza parametri accessibile al codice che crea oggetti da questo
- L'argomento type deve essere un tipo di riferimento oppure deve essere un tipo di valore
Il codice C# può dichiarare che un argomento di tipo deve essere un tipo non gestito . Visual Basic applica questo vincolo per il codice Visual Basic che usa un tipo o un metodo generico definito con questo vincolo (in C#). Tuttavia, non è possibile dichiarare un vincolo unmanaged
su un parametro di tipo in Visual Basic.
Se hai bisogno di imporre più di un requisito, utilizza un elenco di vincoli separati da virgole all'interno di parentesi graffe ({ }
). Per richiedere un costruttore accessibile, includere la parola chiave New Operator nell'elenco. Per richiedere un tipo riferimento, includere la parola chiave Class
; per richiedere un tipo di valore, includere la parola chiave Structure
.
Per altre informazioni sui vincoli, vedere Type List.
Esempio di più vincoli
Nell'esempio seguente viene illustrata una definizione scheletra di una classe generica con un elenco di vincoli nel parametro di tipo . Nel codice che crea un'istanza di questa classe, l'argomento type deve implementare sia le interfacce IComparable che IDisposable, essere un tipo riferimento ed esporre un costruttore senza parametri accessibile.
Public Class thisClass(Of t As {IComparable, IDisposable, Class, New})
' Insert code that defines class members.
End Class
Termini importanti
I tipi generici introducono e usano i termini seguenti:
- tipo generico. Definizione di una classe, una struttura, un'interfaccia, una routine o un delegato per cui si specifica almeno un tipo di dati quando viene dichiarato.
- Tipo Parametro. In una definizione di tipo generico, un segnaposto per un tipo di dati che fornisci quando dichiari il tipo.
- tipo di argomento. Tipo di dati specifico che sostituisce un parametro di tipo quando si dichiara un tipo costruito da un tipo generico.
- vincolo. Condizione per un parametro di tipo che limita l'argomento di tipo che è possibile specificare. Un vincolo può richiedere che l'argomento di tipo implementi una particolare interfaccia, erediti da una determinata classe, abbia un costruttore senza parametri accessibile o sia un tipo di riferimento o un tipo di valore. È possibile combinare questi vincoli, ma è possibile specificare al massimo una classe di base.
- tipo costruito. Classe, struttura, interfaccia, routine o delegato dichiarati da un tipo generico fornendo argomenti di tipo per i relativi parametri di tipo.