值和数组的转换和拆箱有一种奇怪的不一致:
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[]当禁止直接转换时,为什么允许数组拆箱?
发布于 2021-10-04 14:25:35
在禁止直接转换的情况下,为什么允许数组拆箱?
如果使用(int[])(object)us,您将进行两次转换,both of which are allowed by C#
uint[] to object (您可以将任何引用类型转换为object)object to int[] (您可以从object转换为任何引用类型)因此,(int[])(object)us进行了编译。
如果使用(int[])us,您将执行一次从int[]到uint[]的转换,这是C#所不允许的。根据C#规范,只有当T[]和U[]是引用类型时,才能从T转换为U,并且可以从T转换为U。int和uint都不满足这两个条件,因此(int[])us无法编译。
在运行时,检查从uint[]到int[]的转换,看它是成功还是失败。CLR确实允许这样做。请参阅CLR spec的第I.8.7.1节。
签名类型T与签名类型U兼容-当且仅当至少以下一项成立时。
..。
T是一个秩为r,元素类型为V的数组,U是一个秩为r,元素类型为W的数组,V是数组元素兼容的,与W。
..。
签名类型T是数组元素兼容的-当且仅当T具有基础类型V且U具有基础类型W并且:
int和uint的“简化类型”都是int。
这就是(int[])(object)us在运行时成功的原因。
还要注意,将us转换为object并不是“装箱”。这里的一切都是引用类型。您只是更改了引用的类型。
https://stackoverflow.com/questions/69436672
复制相似问题