C#中存储值类型List的object强转IEnumerable<object>失败解决方案
问题根因
直接强转IEnumerable<object>失败是C#泛型协变的规则限制:IEnumerable<out T>的协变特性仅支持引用类型的类型参数转换,值类型存在装箱转换流程,不满足泛型协变的类型匹配要求,因此List<int>、List<(int,int)>等值类型集合无法直接转换为IEnumerable<object>,和类型转换运算符无关。
兼容实现方案
所有泛型List<T>无论T是值类型还是引用类型,都实现了非泛型接口System.Collections.IEnumerable,可以先将入参转换为非泛型可枚举接口,再通过LINQ的Cast<object>()方法完成到IEnumerable<object>的转换,该方法会自动处理引用类型转换、值类型装箱的逻辑,完全不需要提前获知T的实际类型。
完整代码实现
需要先引入两个必要命名空间:
using System.Collections; using System.Linq;
方法实现如下:
void Receive(object collection) { // 第一步:转非泛型IEnumerable,所有List<T>都能完成这步转换,无类型风险 var enumerable = (IEnumerable)collection; // 第二步:转IEnumerable<object>,自动兼容值类型、引用类型集合 IEnumerable<object> objectCollection = enumerable.Cast<object>(); // 如果需要具体的List<object>类型,直接追加ToList()即可 // List<object> objectList = enumerable.Cast<object>().ToList(); }
兼容性说明
- 传入引用类型集合(如
List<Foo>):转换过程为直接引用转换,无额外性能损耗 - 传入值类型集合(如
List<int>、List<(int,int)>):遍历过程自动完成值类型装箱,可正常运行不会抛出类型转换异常 - 该写法同时兼容所有实现了非泛型
IEnumerable的其他集合类型(如数组、HashSet<T>等),后续如果入参类型扩展也不需要修改逻辑 - 如果需要做防御性编程,可以用模式匹配做安全转换并判空,避免非法入参触发类型转换异常:
if (collection is not IEnumerable enumerable) { // 自定义非法入参处理逻辑 return; }
注意:不存在零开销的值类型集合转
IEnumerable<object>的方案,值类型转object必须经过装箱流程,这是CLR类型系统的固有规则决定的。
内容的提问来源于stack exchange,提问作者user1314926
相关产品推荐
相关产品推荐

