La definición de cada tipo que se deriva de System.ValueType
, con la excepción de System.Enum
, en realidad define dos tipos de cosas: un tipo de objeto montón, y un tipo de almacenamiento en la ubicación. Las instancias de este último pueden convertirse implícitamente en el primero (haciendo una copia de los datos contenidos en él), y las instancias del primero pueden ser explícitamente encasilladas a este último (del mismo modo); a pesar de que ambos tipos de cosas se describen por el mismo System.Type
, y aunque tienen los mismos miembros, se comportan de manera muy diferente.
A List<AnyClassType>
esperará contener un montón de referencias de objetos de montón; si la lista en cuestión es List<String>
, List<StringBuilder>
, List<Button>
, o lo que sea, puede ser de interés para los usuarios de la lista, pero realmente no interesa al List<T>
. Si se lanza un List<Button>
a un IEnumerable<Control>
, alguien que llame a su método GetEnumerator()
esperará obtener un objeto que generará referencias a los objetos del montón que derivan de Control
; el retorno de List<Button>.GetEnumerator()
satisfará esa expectativa.Por el contrario, si alguien lanzara List<Int32>
a List<Object>
, alguien que llamara GetEnumerator()
esperaría algo que generaría referencias de objetos de montón, pero List<Integer>.GetEnumerator
arrojará algo que emita enteros de tipo valor.
Es posible almacenar Int32
valores en un List<Object>
o un List<ValueType>
; almacenar un número entero en dicha lista lo convertirá en su forma de objeto de montón y almacenará una referencia a él; llamar al GetEnumerator()
arrojaría algo que genere referencias de montón. Sin embargo, no hay forma de especificar que dicha lista solo contendrá instancias del tipo de pila correspondiente al Int32
. En C++/CLI, es posible declarar variables del tipo "referencia al tipo de valor almacenado en el montón", pero los mecanismos detrás de los tipos genéricos en .net no pueden funcionar con dichos tipos.
Pero Int32 se puede convertir en Objeto. ¿No es eso suficiente para hacer una covarianza? ¿O es una característica del compilador? – Vasaka
@Vasaka: Es una operación de boxeo y no una conversión de referencia. Es técnico, pero a pesar de la sintaxis idéntica, lo que el compilador realmente hace en cada caso es totalmente diferente. – Jon
... como son los parámetros de tipo de todas las clases y estructuras genéricas; type varianza soportada solo para interfaces y tipos de delegados. – phoog