ACTUALIZACIÓN: He usado esta pregunta como base para una entrada de blog, aquí:
http://blogs.msdn.com/ericlippert/archive/2009/09/24/why-is-covariance-of-value-typed-arrays-inconsistent.aspx
Ver los comentarios del blog para una extensa discusión de este problema. Gracias por la gran pregunta!
Usted ha tropezado con una inconsistencia interesante y lamentable entre el sistema de tipo CLI y el sistema de tipo C#.
La CLI tiene el concepto de "compatibilidad de asignación". Si un valor x del tipo de datos conocidos S es "compatible con la asignación" con una ubicación de almacenamiento particular y de tipo de datos conocidos T, entonces puede almacenar x en y. De lo contrario, hacerlo no es un código verificable y el verificador no lo permitirá.
El sistema de tipo CLI dice, por ejemplo, que los subtipos de tipo de referencia son compatibles con supertipos de tipo de referencia. Si tiene una cadena, puede almacenarla en una variable de tipo objeto, porque ambos son tipos de referencia y la cadena es un subtipo de objeto. Pero lo opuesto no es verdad; los supertipos no son compatibles con subtipos. No se puede pegar algo que se sabe que es un objeto en una variable de tipo cadena sin primero echarlo.
Básicamente "asignación compatible" significa que "tiene sentido pegar estos bits exactos en esta variable". La asignación del valor de origen a la variable de destino debe ser "conservación de representación". Véase mi artículo sobre que para más detalles:
http://ericlippert.com/2009/03/03/representation-and-identity/
Una de las reglas de la CLI es "si X es compatible con la asignación y, entonces x [] es compatible con la asignación Y []".
Es decir, las matrices son covariantes con respecto a la compatibilidad de asignación. Esto es realmente un tipo roto de covarianza; ver mi artículo sobre eso para más detalles.
http://blogs.msdn.com/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx
Eso no es una regla de C#. La regla de covarianza de la matriz C# es "si X es un tipo de referencia implícitamente convertible a la clase de referencia Y, entonces X [] es implícitamente convertible a Y []". Esa es una regla sutilmente diferente, y por lo tanto su situación confusa.
En la CLI, uint e int son asignaciones de tareas. Pero en C#, la conversión entre int y uint es EXPLÍCITA, no IMPLÍCITA, y estos son tipos de valores, no tipos de referencia. Entonces en C#, no es legal convertir un int [] en un uint [].
Pero ES legal en la CLI. Entonces ahora nos enfrentamos con una elección.
1) Implementar "es" para que cuando el compilador no pueda determinar la respuesta estáticamente, realmente llame a un método que verifique todas las reglas de C# para la convertibilidad que preserve la identidad. Esto es lento, y el 99.9% del tiempo coincide con las reglas de CLR. Pero aprovechamos el rendimiento para ser 100% compatibles con las reglas de C#.
2) Implementar "es" para que cuando el compilador no pueda determinar la respuesta estáticamente, haga la increíblemente rápida verificación de compatibilidad de asignación CLR, y viva con el hecho de que esto indica que uint [] es un int [], a pesar de que eso no sería legal en C#.
Elegimos este último. Es desafortunado que C# y las especificaciones CLI estén en desacuerdo en este punto menor, pero estamos dispuestos a vivir con la inconsistencia.
Gran lectura. Gracias por la respuesta. –
Hola Eric, por curiosidad, ¿decidieron aceptar esta incoherencia o no estaba previsto? Sólo me preguntaba. –
Eliminé mi publicación por deferencia a una respuesta mucho mejor y más profunda. – LBushkin