Hay una extraña inconsistencia con la conversión y desempaquetado de valores y matrices:
var us = new uint[] { 1, 2, 3 }; var i1 = (int)us[0]; // direct value to value: works var i2 = (int)(object)us[0]; // unboxing value to value: compiles, throws at runtime var is1 = (int[])u; // direct array to array: does not compile var is2 = (int[])(object)u; // unboxing array to array: works! is2.GetType().Name // UInt32[]¿Por qué se permite el desempaquetado de matrices cuando está prohibida una conversión directa?
¿Por qué se permite el desempaquetado de matrices cuando está prohibida una conversión directa?
Si hace (int[])(object)us , está realizando dos conversiones, ambas permitidas por C# :
uint[] a object (puede convertir cualquier tipo de referencia a object )object to int[] (puede convertir desde object a cualquier tipo de referencia) Por lo tanto (int[])(object)us compila.
Si lo hace (int[])us , está realizando una sola conversión de int[] a uint[] , lo cual no está permitido en C#. De acuerdo con la especificación de C#, solo puede convertir de T[] a U[] si T y U son tipos de referencia, y puede convertir de T a U . int y uint no satisfacen ninguno de esos, por lo que (int[])us no compila.
En tiempo de ejecución, se comprueba la conversión de uint[] a int[] para ver si tiene éxito o falla. El CLR permite esto. Consulte la sección I.8.7.1 de la especificación CLR .
Una firma tipo T es compatible con una firma tipo U si y solo si se cumple al menos uno de los siguientes.
[...]
T es una matriz con el rango r y el tipo de elemento V, y U es una matriz con el mismo rango r y el tipo de elemento W, y V es una matriz-elemento-compatible-con W.
[...]
Un tipo de firma T es compatible con elementos de matriz con un tipo de firma U si y solo si T tiene un tipo subyacente V y U tiene un tipo subyacente W y cualquiera de los siguientes:
- V es compatible con W; o
- V y W tienen el mismo tipo reducido.
Y los "tipos reducidos" de int y uint son ambos int .
Esta es la razón por la cual (int[])(object)us tiene éxito en tiempo de ejecución.
También tenga en cuenta que us a object no es "boxear". Todo es un tipo de referencia aquí. Solo estás cambiando el tipo de la referencia.