Che cosa è esattamente un “open generico tipo” in .NET?[duplica]
-
24-09-2019 - |
Domanda
A questa domanda ha già una risposta qui:
Stavo attraversando Asp.Net MVC lezione e ho imparato che, per un metodo per qualificarsi come azione per un controller,
- Non deve avere un "aprire generico tipo"
Capisco un po ' generici e li usa in una certa misura, ma:
- Che cosa è un tipo generico aperto in .Net.
- C'è una tale cosa come un chiuso di tipo generico?
- Tipo generico aperto è un termine che non viene utilizzato molto spesso.Che cosa è utilizzato / confuso con esso ?
Soluzione
Il linguaggio C # definisce un tipo aperto per essere un tipo che è sia un argomento di tipo o di un tipo generico definito con argomenti di tipo sconosciuto:
Tutti i tipi possono essere classificate come tipi aperti o chiusi i tipi. Un tipo aperto è un tipo che coinvolge parametri di tipo. Più in particolare:
- parametro Un tipo definisce un tipo aperto.
- Un tipo di matrice è del tipo aperto se e solo se il suo tipo di elemento è del tipo aperto.
- A tipo costruito è del tipo aperto se e solo se uno o più dei suoi argomenti di tipo è un tipo aperto . A tipo annidato costruito è un tipo aperto se e solo se uno o più dei suoi argomenti o di tipo argomenti di questo tipo contenenti (s) è del tipo aperto.
tipo chiuso è un tipo che non è del tipo aperto.
Pertanto T
, List<T>
e Dictionary<string,T>
e Dictionary<T,U>
sono tutti i tipi aperti (T
e U
sono argomenti di tipo) mentre List<int>
e Dictionary<string,int>
sono tipi chiusi.
C'è un concetto relativo: un non legato tipo generico è un tipo generico con argomenti di tipo non specificato. Un tipo non legato non può essere utilizzato nelle espressioni diverse typeof()
e non è possibile creare un'istanza o chiamare i suoi metodi. Per esempio, List<>
e Dictionary<,>
sono tipi non legati.
Per chiarire la sottile distinzione tra un tipo aperto e di tipo non legato:
class Program {
static void Main() { Test<int>(); }
static void Test<T>() {
Console.WriteLine(typeof(List<T>)); // Print out the type name
}
}
Se si esegue questo frammento di codice, sarà stampare
System.Collections.Generic.List`1[System.Int32]
che è il nome CLR per List<int>
. E 'chiaro in fase di esecuzione che l'argomento tipo è System.Int32
. Questo rende List<T>
un legato tipo aperto.
In fase di runtime, è possibile utilizzare la reflection per argomenti di tipo si legano ai parametri di tipo non specificato di tipi generici non legati con il metodo Type.MakeGenericType
:
Type unboundGenericList = typeof(List<>);
Type listOfInt = unboundGenericList.MakeGenericType(typeof(int));
if (listOfInt == typeof(List<int>))
Console.WriteLine("Constructed a List<int> type.");
È possibile controllare se un tipo è un tipo generico non legato ( definizione di tipo generico ) da cui è possibile costruire tipi rilegati con la Type.IsGenericTypeDefinition
proprietà :
Console.WriteLine(typeof(Dictionary<,>).IsGenericTypeDefinition); // True
Console.WriteLine(typeof(Dictionary<int,int>).IsGenericTypeDefinition); // False
Per ottenere il tipo non legato da un tipo costruito in fase di esecuzione, è possibile utilizzare il Type.GetGenericTypeDefinition
metodo .
Type listOfInt = typeof(List<int>);
Type list = listOfInt.GetGenericTypeDefinition(); // == typeof(List<>)
Si noti che per un tipo generico, è possibile avere una definizione di tipo completamente non legato, o una definizione completamente vincolata. Si può non vincola alcuni parametri di tipo e altri lasciano non legato. Per esempio, non si può avere Dictionary<int,>
o Dictionary<,string>
.
Altri suggerimenti
Giusto per aggiungere:
Dictionary<string, T>
(o più precisamente Dictionary<string,>
) è ancora un tipo aperto.
Esempio:
void Foo<T>(Dictionary<string,T> dic) { ... }
Un "aperto tipo generico" è solo un tipo generico che non c'è ancora il tipo specificato (ad esempio, CargoCrate<T>
). Si diventa "chiuso" una volta un tipo concreto è stato assegnato (ad esempio CargoCrate<Widget>
).
Per esempio, supponiamo di avere qualcosa di simile:
public class Basket<T> {
T[] basketItems;
}
public class PicnicBlanket<T> {
Basket<T> picnicBasket; // Open type here. We don't know what T is.
}
// Closed type here: T is Food.
public class ParkPicnicBlanket : PicnicBlanket<Food> {
}
Qui, il tipo di picnicBasket
è aperto: nulla è stato ancora assegnato a T
. Quando si effettua una PicnicBlanket cemento con un tipo specifico - ad esempio, scrivendo PicnicBlanket<Food> p = new PicnicBlanket<Food>()
- noi ora chiamiamo chiuso
Ci sono tre tipi di tipi generici.Per farla breve, in questo (semplificato) dichiarazione:
public class Dictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
Dictionary<TKey, TValue>
è un sovrabbondanza di tipo generico.KeyValuePair<TKey, TValue>
è, in questo caso, un costruito aperto di tipo generico.Ha alcuni parametri di tipo, ma sono già definiti altrove (in Dizionario, in questo caso).Dictionary<string, int>
sarebbe un costruito chiuso di tipo generico.