There is a weird inconsistency with converting and unboxing values and arrays:
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[]
Why is array unboxing allowed, when a direct conversion is prohibited?
If you do
(int[])(object)us, you are doing two conversions, both of which are allowed by C#:uint[]toobject(you are allowed to cast any reference type toobject)objecttoint[](you are allowed to cast fromobjectto any reference type)Therefore
(int[])(object)uscompiles.If you do
(int[])us, you are doing a single conversion fromint[]touint[], which is not allowed by C#. According to the C# spec, you can only cast from aT[]toU[]ifTandUare reference types, and that you can cast fromTtoU.intanduintsatisfy neither of those, so(int[])usdoes not compile.At runtime, the cast from
uint[]toint[]is checked to see if it succeeds or fails. The CLR does allow this. See section I.8.7.1 of the CLR spec.And the "reduced types" of
intanduintare bothint.This is why
(int[])(object)ussucceeds at runtime.Also note that casting
ustoobjectis not "boxing". Everything is a reference type here. You're just changing the type of the reference.