Genéricos: tipos construidos abiertos y cerrados

Recientemente noté que los tipos construidos generics pueden ser abiertos y cerrados. Pero no entiendo lo que realmente significan. ¿Puedes dar un ejemplo simple?

En la práctica, la terminología en realidad no importa mucho; no recuerdo la última vez que tuve que preocuparme de ella, excepto cuando intentaba escribir sobre ella.

  • Un tipo no vinculado no tiene ningún tipo de argumentos especificados
  • Un tipo construido tiene al menos un tipo de argumento especificado
  • Un parámetro de tipo es un tipo abierto
  • Un tipo de matriz donde el tipo de elemento está abierto es un tipo abierto
  • Un tipo abierto construido tiene al menos un argumento tipo que es un tipo abierto
  • Un tipo cerrado es cualquier tipo que no esté abierto

(Hay otras reglas para los tipos nesteds. Consulte la sección de especificaciones de C # 3.0 4.4 para obtener detalles sangrientos).

Como ejemplo de un tipo abierto construido, considere:

public class NameDictionary : Dictionary 

La clase base de typeof(NameDictionary<>) es:

  • Construido porque especifica argumentos de tipo
  • Abierto porque el segundo argumento de tipo ( T ) es un tipo abierto

Los documentos de MSDN para Type.IsGenericType tienen una tabla bastante útil.

Solo para reiterar, esto es casi completamente sin importancia en el uso diario.

En general, estoy a favor de conocer la terminología correcta, particularmente para cosas como “pasar por referencia”, etc., pero en este caso, realmente, no aparece muy a menudo. Me gustaría desanimarlo activamente para que no se preocupe por eso 🙂

Desde MSDN :

Un tipo o método genérico se cierra si se han sustituido los tipos de instancia para todos sus parámetros de tipo, incluidos todos los parámetros de tipo de todos los tipos adjuntos. Solo puede crear una instancia de un tipo genérico si está cerrado.

Esto funciona cuando List está cerrado :

 var list = Activator.CreateInstance(typeof(List)); 

Pero esto arroja una excepción en el tiempo de ejecución porque List<> está abierto :

 var list = Activator.CreateInstance(typeof(List<>)); ↑ 

En su mayoría he usado generics abiertos (generics básicamente desinstalados) en mapeos de dependency injection. Por ejemplo, algo así como

 Bind>() .To>() 

Entonces, cuando mi constructor de objetos contiene:

 public SomethingController(IRepository) { ... } 

Mi mecanismo de dependency injection instanciará un BasicRepository automágicamente. (Esto funciona con Ninject y StructureMap, y probablemente con la biblioteca Castle Windsor; no estoy seguro de otros frameworks).