Reflection e tipi generici
Dal punto di vista della reflection, un tipo ordinario si differenzia da un tipo generico perché quest'ultimo è associato a un insieme di parametri di tipo, se è una definizione di tipo generico, o a un insieme di argomenti di tipo, se è un tipo costruito. Un metodo generico si differenzia da un metodo ordinario esattamente nello stesso modo.
Per comprendere come i tipi e i metodi generici vengono gestiti dalla reflection, è opportuno considerare due fattori fondamentali:
I parametri di tipo delle definizioni di tipo e di metodo generico sono rappresentati da istanze della classe Type.
Nota Numerosi metodi e proprietà di Type hanno un comportamento differente quando un oggetto Type rappresenta un parametro di tipo generico.Queste differenze sono illustrate negli argomenti relativi alle proprietà e ai metodi in questione.Vedere ad esempio IsAutoClass e DeclaringType.Inoltre, alcuni membri sono validi solo quando un oggetto Type rappresenta un parametro di tipo generico.Vedere ad esempio GetGenericTypeDefinition.
Se un'istanza di Type rappresenta un tipo generico, includerà una matrice di tipi che rappresentano i parametri di tipo (per le definizioni di tipo generico) o gli argomenti di tipo (per i tipi costruiti). Questo è vero anche per un'istanza della classe MethodInfo che rappresenta un metodo generico.
La reflection fornisce metodi di Type e MethodInfo che consentono di accedere alla matrice di parametri di tipo e stabilire se un'istanza di Type rappresenta un parametro di tipo o un tipo effettivo.
Per il codice di esempio in cui sono illustrati i metodi indicati in questo argomento, vedere Procedura: esaminare e creare istanze di tipi generici tramite reflection.
Nelle considerazioni che seguono si presuppone che siano noti i concetti di base relativi ai generics, ad esempio la differenza tra argomenti e parametri di tipo e quella tra tipi costruiti aperti o chiusi. Per ulteriori informazioni, vedere Generics in .NET Framework.
In questa panoramica sono incluse le sezioni seguenti:
Come stabilire se un tipo o un metodo è generico
Generazione di tipi generici chiusi
Analisi degli argomenti e dei parametri di tipo
Condizioni non variabili
Argomenti correlati
Come stabilire se un tipo o un metodo è generico
Quando si esamina un tipo sconosciuto rappresentato da un'istanza di Type tramite la reflection, utilizzare la proprietà IsGenericType per stabilire se il tipo è generico. In caso affermativo, la proprietà restituisce true. Analogamente, quando si esamina un metodo sconosciuto rappresentato da un'istanza della classe MethodInfo, utilizzare la proprietà IsGenericMethod per stabilire se il metodo è generico.
Come stabilire se un oggetto rappresenta una definizione di metodo o di tipo generico
Utilizzare la proprietà IsGenericTypeDefinition per stabilire se un oggetto Type rappresenta una definizione di tipo generico e il metodo IsGenericMethodDefinition per determinare se un oggetto MethodInfo rappresenta una definizione di metodo generico.
Le definizioni di metodo e di tipo generico costituiscono i modelli a partire dai quali vengono generati i tipi di cui è possibile creare istanze. I tipi generici nella libreria di classi .NET Framework, ad esempio Dictionary<TKey, TValue>, sono definizioni di tipo generico.
Come stabilire se un tipo o un metodo è aperto o chiuso
Un tipo o un metodo generico è chiuso se tutti i relativi parametri di tipo, inclusi tutti i parametri di tipo di tutti i tipi di inclusione, sono stati sostituiti da tipi di cui è possibile creare istanze. È possibile creare un'istanza di un tipo generico solo se quest'ultimo è chiuso. Se un tipo è aperto, la proprietà Type.ContainsGenericParameters restituisce true. Per i metodi, la stessa funzione viene svolta dal metodo MethodInfo.ContainsGenericParameters.
Torna all'inizio
Generazione di tipi generici chiusi
Non appena si dispone di una definizione di metodo o di tipo generico, utilizzare il metodo MakeGenericType per creare un tipo generico chiuso oppure il metodo MakeGenericMethod per creare un oggetto MethodInfo relativo a un metodo generico chiuso.
Recupero della definizione di tipo o di metodo generico
Se si dispone di un tipo o di un metodo generico aperto che non è una definizione di tipo o di metodo generico, non è possibile crearne istanze né specificare i parametri di tipo mancanti. A tale scopo è necessario disporre di una definizione di tipo o di metodo generico. Utilizzare il metodo GetGenericTypeDefinition per ottenere la definizione di tipo generico o il metodo GetGenericMethodDefinition per ottenere la definizione di metodo generico.
Se ad esempio si dispone di un oggetto Type che rappresenta Dictionary<int, string> (Dictionary(Of Integer, String) in Visual Basic) e si desidera creare il tipo Dictionary<string, MyClass>, è possibile utilizzare il metodo GetGenericTypeDefinition per ottenere un oggetto Type che rappresenta Dictionary<TKey, TValue> e quindi il metodo MakeGenericType per generare un oggetto Type che rappresenta Dictionary<int, MyClass>.
Per un esempio di tipo generico aperto che non è un tipo generico, vedere la sezione "Parametro di tipo o argomento di tipo" più avanti in questo argomento.
Torna all'inizio
Analisi degli argomenti e dei parametri di tipo
Utilizzare il metodo Type.GetGenericArguments per ottenere una matrice di oggetti Type che rappresentano i parametri o gli argomenti di tipo di un tipo generico e il metodo MethodInfo.GetGenericArguments per eseguire la stessa operazione per un metodo generico.
Una volta stabilito che un oggetto Type rappresenta un parametro di tipo, la reflection consentirà di ottenere ulteriori informazioni al riguardo. È possibile determinare l'origine, la posizione e i vincoli del parametro di tipo.
Parametro di tipo o argomento di tipo
Per stabilire se un determinato elemento della matrice è un parametro di tipo oppure un argomento di tipo, utilizzare la proprietà IsGenericParameter. Se l'elemento è un parametro di tipo, la proprietà IsGenericParameter restituisce true.
Un tipo generico può essere aperto senza essere una definizione di tipo generico. In tal caso, presenterà sia argomenti di tipo che parametri di tipo. Nel codice riportato di seguito, ad esempio, la classe D deriva da un tipo creato sostituendo il primo parametro di tipo di D al secondo parametro di tipo di B.
class B<T, U> {}
class D<V, W> : B<int, V> {}
Class B(Of T, U)
End Class
Class D(Of V, W)
Inherits B(Of Integer, V)
End Class
generic<typename T, typename U> ref class B {};
generic<typename V, typename W> ref class D : B<int, V> {};
Se si ottiene un oggetto Type che rappresenta D<V, W> e si utilizza la proprietà BaseType per recuperarne il tipo base, il type B<int, V> risultante sarà aperto, ma non sarà una definizione di tipo generico.
Origine di un parametro generico
Un parametro di tipo generico può provenire dal tipo in esame, da un tipo di inclusione o da un metodo generico. È possibile determinarne l'origine nel modo seguente:
Innanzitutto, utilizzare la proprietà DeclaringMethod per stabilire se il parametro di tipo proviene da un metodo generico. Se il valore della proprietà non è un riferimento null (Nothing in Visual Basic), l'origine è un metodo generico.
Se l'origine non è un metodo generico, utilizzare la proprietà DeclaringType per determinare il tipo generico a cui appartiene il parametro di tipo generico.
Se il parametro di tipo appartiene a un metodo generico, la proprietà DeclaringType restituisce il tipo che ha dichiarato tale metodo, che non è un'informazione rilevante.
Posizione di un parametro generico
In rare situazioni è necessario stabilire la posizione di un parametro di tipo nell'elenco dei parametri di tipo della classe dichiarante. Si supponga ad esempio di disporre di un oggetto Type che rappresenta il tipo B<int, V> dell'esempio precedente. Il metodo GetGenericArguments fornisce un elenco di argomenti di tipo ed è possibile determinare l'origine del parametro V in esame utilizzando le proprietà DeclaringMethod e DeclaringType. È quindi possibile utilizzare la proprietà GenericParameterPosition per stabilire la posizione del parametro nell'elenco dei parametri del tipo in cui il parametro è stato definito. In questo esempio, V si trova nella posizione 0 (zero) dell'elenco.
Vincoli di interfaccia e del tipo base
Utilizzare il metodo GetGenericParameterConstraints per ottenere il vincolo del tipo base e i vincoli di interfaccia di un parametro di tipo. L'ordine degli elementi della matrice non è significativo. Un elemento rappresenta un vincolo di interfaccia se è un tipo di interfaccia.
Attributi di parametri generici
La proprietà GenericParameterAttributes ottiene un valore GenericParameterAttributes che indica la varianza (covarianza o controvarianza) e i vincoli speciali di un parametro di tipo.
Covarianza e controvarianza
Per stabilire se un parametro di tipo sia covariante o controvariante, applicare la maschera GenericParameterAttributes.VarianceMask al valore GenericParameterAttributes restituito dalla proprietà GenericParameterAttributes. Se il risultato è GenericParameterAttributes.None, il parametro di tipo è invariante. Vedere Covarianza e controvarianza nei generics.
Vincoli speciali
Per stabilire i vincoli speciali di un parametro di tipo, applicare la maschera GenericParameterAttributes.SpecialConstraintMask al valore GenericParameterAttributes restituito dalla proprietà GenericParameterAttributes. Se il risultato è GenericParameterAttributes.None, non sono presenti vincoli speciali. Un parametro di tipo può essere vincolato a essere un tipo di riferimento, un tipo di valore non nullable e ad avere un costruttore predefinito.
Torna all'inizio
Condizioni non variabili
Per una tabella di condizioni non variabili associate a termini comuni nella reflection per tipi generici, vedere Type.IsGenericType. Per termini aggiuntivi correlati ai metodi generici, vedere MethodInfo.IsGenericMethod.
Torna all'inizio
Argomenti correlati
Titolo |
Descrizione |
---|---|
Procedura: esaminare e creare istanze di tipi generici tramite reflection |
Viene illustrato come utilizzare le proprietà e i metodi di Type e MethodInfo per esaminare i tipi generici. |
Viene descritta la funzionalità generics con la relativa modalità di supporto in .NET Framework. |
|
Procedura: definire un tipo generico tramite reflection emit |
Viene illustrato come utilizzare la reflection emit per generate tipi generici in assembly dinamici. |
Viene illustrata la classe Type e vengono forniti esempi di codice in cui viene descritto come utilizzare Type con diverse classi reflection per ottenere informazioni su costruttori, metodi, campi, proprietà ed eventi. |
Torna all'inizio