¿Qué es exactamente un “tipo genérico abierto” en .NET? [duplicar]
-
24-09-2019 - |
Pregunta
Esta pregunta ya tiene una respuesta aquí:
- Generics -Abrir y tipos construidos cerradas 3 respuestas
Yo estaba pasando por Asp.Net MVC lección y aprendido que, para un método para calificar como una acción de un controlador,
- No debe tener un "tipo genérico abierto"
entiendo un poco genéricos y los utilizo en cierta medida, pero:
- ¿Qué es un tipo genérico abierto en .Net.
- ¿Hay una cosa tal como un tipo genérico cerrado ?
- tipo genérico Abrir es un término no se usa muy a menudo. Lo que se usa / confundirse con ella?
Solución
El lenguaje C # define un tipo abierto para ser un tipo que de ya sea un argumento tipo o un tipo genérico definido con argumentos de tipo desconocido:
Todos los tipos se pueden clasificar como cualquiera de los tipos abiertos o tipos cerrados. Un tipo abierto es un tipo que involucra a los parámetros de tipo. Más específicamente:
- parámetro A tipo define un tipo abierto.
- un tipo de matriz es un tipo abierto si y sólo si su tipo de elemento es un tipo abierto.
- A tipo construido es un tipo abierto si y sólo si una o más de sus argumentos de tipo es un tipo abierto . A tipo anidado construido es un tipo abierto si y sólo si una o más de sus argumentos de tipo o de los argumentos de tipo de su tipo que contienen (s) es un tipo abierto.
tipo cerrado es un tipo que no es un tipo abierto.
Por lo tanto T
, List<T>
, y Dictionary<string,T>
, y Dictionary<T,U>
son todos los tipos abiertos (T
y U
son argumentos de tipo), mientras que List<int>
y Dictionary<string,int>
son tipos cerrados.
No es un concepto relacionado: Un tipo genérico no unido es un tipo genérico con argumentos de tipo no especificado. Un tipo no unida no puede usarse en expresiones que no sean typeof()
y no se puede crear una instancia o llamar a sus métodos. Por ejemplo, List<>
y Dictionary<,>
son tipos no unidos.
Para aclarar la sutil distinción entre un tipo abierto y un tipo sin unir:
class Program {
static void Main() { Test<int>(); }
static void Test<T>() {
Console.WriteLine(typeof(List<T>)); // Print out the type name
}
}
Si ejecuta este fragmento, que va a imprimir
System.Collections.Generic.List`1[System.Int32]
que es el nombre de CLR para List<int>
. Está claro que en tiempo de ejecución es el argumento de tipo System.Int32
. Esto hace List<T>
un con destino de tipo abierto.
En tiempo de ejecución, se puede utilizar la reflexión a argumentos de tipo se unen a los parámetros de tipo no especificado de tipos genéricos no unidas con el método Type.MakeGenericType
:
Type unboundGenericList = typeof(List<>);
Type listOfInt = unboundGenericList.MakeGenericType(typeof(int));
if (listOfInt == typeof(List<int>))
Console.WriteLine("Constructed a List<int> type.");
Se puede comprobar si un tipo es un tipo genérico no unida ( tipo genérico definición ) desde el que se puede construir tipos ligados a la Type.IsGenericTypeDefinition
propiedad :
Console.WriteLine(typeof(Dictionary<,>).IsGenericTypeDefinition); // True
Console.WriteLine(typeof(Dictionary<int,int>).IsGenericTypeDefinition); // False
Para obtener el tipo no unido de un tipo construido en tiempo de ejecución, se puede utilizar el Type.GetGenericTypeDefinition
método .
Type listOfInt = typeof(List<int>);
Type list = listOfInt.GetGenericTypeDefinition(); // == typeof(List<>)
Tenga en cuenta que para un tipo genérico, que o bien puede tener una definición de tipo completamente sin consolidar o una definición completamente atado. Puede no se unen algunos parámetros de tipo y dejar que otros no unido. Por ejemplo, no se puede tener Dictionary<int,>
o Dictionary<,string>
.
Otros consejos
Sólo para añadir:
Dictionary<string, T>
(o más precisamente Dictionary<string,>
) es todavía un tipo abierto.
Ejemplo:
void Foo<T>(Dictionary<string,T> dic) { ... }
Un "tipo genérico abierto" es sólo un tipo genérico que no tienen todavía su tipo especificado (por ejemplo, CargoCrate<T>
). Se convierte en "cerrado" una vez que se ha asignado un tipo concreto (por ejemplo CargoCrate<Widget>
).
Por ejemplo, supongamos que tiene algo como esto:
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> {
}
A continuación, el tipo de picnicBasket
está abierto: nada todavía ha sido asignado a T
. Cuando haces una PicnicBlanket hormigón con un tipo específico - por ejemplo, escribiendo PicnicBlanket<Food> p = new PicnicBlanket<Food>()
- ahora lo llamamos cerrado
Hay tres clases de tipos genéricos. Para ser breves, en esta declaración (simplificado):
public class Dictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
-
Dictionary<TKey, TValue>
es un tipo genérico sin límites . -
KeyValuePair<TKey, TValue>
es, en este caso, un abierto construido tipo genérico . Tiene algunos parámetros de tipo, pero que ya se definen en otra parte (en el diccionario, en este caso). -
Dictionary<string, int>
sería un Cerrado construido tipo genérico .