C#中如何将实现接口的类列表转换为对应接口列表?
这是C#里很常见的泛型协变相关问题,我来一步步帮你理清原因和解决办法:
为什么直接转换会报错?
C#中的List<T>是不变类型——简单说就是,哪怕Test_Class1实现了Demo_Interface,List<Test_Class1>也不能直接被当作List<Demo_Interface>使用。
背后的逻辑是:如果允许这种转换,那你完全可以在Output_Class方法里往inter_input里添加一个Test_Class2的实例,但原列表class_list_1本质上只能存储Test_Class1类型,这就会导致类型不匹配的错误,C#在编译阶段就会阻止这种潜在风险。
三种可行的解决方案
方案1:用LINQ转换生成新列表
通过LINQ的Cast<T>()方法把每个元素转换成接口类型,再生成新的List<Demo_Interface>:
// 修改Main里的调用代码 Output_Class(new_main_class.class_list_1.Cast<Demo_Interface>().ToList());
如果担心列表里有不符合接口的元素(你的场景里不会有),可以用OfType<Demo_Interface>()代替Cast,它会自动过滤掉不匹配的元素。
方案2:把方法改成泛型方法(推荐,无需额外生成列表)
修改Output_Class方法,添加泛型约束,让它支持所有实现Demo_Interface的类型:
static void Output_Class<T>(List<T> inter_input) where T : Demo_Interface { for (int i = 0; i < inter_input.Count; i++) { Console.WriteLine("{0} - {1}",i, inter_input[i].test_int); } }
这样调用的时候直接传原列表就行,不需要任何转换:
Output_Class(new_main_class.class_list_1); // 现在不会报错了
这种方式更高效,因为不需要创建新的列表实例。
方案3:改用协变接口IEnumerable<Demo_Interface>
如果Output_Class方法只需要遍历读取数据,不需要修改列表,可以把参数类型改成IEnumerable<Demo_Interface>——因为IEnumerable<T>是协变的,允许隐式转换:
static void Output_Class(IEnumerable<Demo_Interface> inter_input) { int index = 0; foreach (var item in inter_input) { Console.WriteLine("{0} - {1}", index++, item.test_int); } }
调用时同样直接传原列表即可,List<Test_Class1>会自动隐式转换成IEnumerable<Demo_Interface>。
内容的提问来源于stack exchange,提问作者user11472260

