C#中IList<实现类>无法转换为IList<接口>的问题求助
核心原因:IList是不变类型
C#里的IList<T>属于不变泛型类型,哪怕ReorderPositionsFakeModel实现了IPosition,IList<ReorderPositionsFakeModel>和IList<IPosition>也会被编译器视为完全不同的类型,不能直接转换。
这是因为IList<T>同时支持读、写操作:如果允许转换,你可以通过IList<IPosition>的接口往集合里加入另一个实现IPosition的类(比如OtherPositionModel),但原集合实际只能存储ReorderPositionsFakeModel类型,这会触发运行时类型错误——编译器提前拦住了这种不安全操作。
可行解决方案
1. 把方法参数换成协变的IEnumerable<IPosition>
如果你的Reorder方法只需要读取集合元素(不需要添加、修改元素),可以把参数改成IEnumerable<IPosition>。因为IEnumerable<out T>是协变类型(out关键字表示只能输出T,不能输入),IList<ReorderPositionsFakeModel>继承了IEnumerable<ReorderPositionsFakeModel>,自然能转成IEnumerable<IPosition>:
public static class ReorderPositions { public static void Reorder(IEnumerable<IPosition> positions) { // 你的排序逻辑,只读取元素的话完全没问题 } }
2. 改成带类型约束的泛型方法
如果必须保留IList<T>的写入能力,就把Reorder改成泛型方法,给类型参数加IPosition的约束:
public static class ReorderPositions { public static void Reorder<T>(IList<T> positions) where T : IPosition { // 排序逻辑,此时操作集合是安全的,因为T是具体的实现类 } }
调用时直接传IList<ReorderPositionsFakeModel>就行,编译器会自动识别泛型参数。
3. 手动转换集合类型
如果不想改方法签名,调用时可以把集合转成IList<IPosition>,比如用Cast<IPosition>()配合ToList():
var fakeModels = Factory.CreateFakeModels(); // IList<ReorderPositionsFakeModel> ReorderPositions.Reorder(fakeModels.Cast<IPosition>().ToList());
注意:ToList()会创建新集合,原集合不会被修改;如果需要修改原集合,别用这个方案,优先选方案2。
内容的提问来源于stack exchange,提问作者Oleg Sh

