C#中如何将派生类集合传入接收基类集合的方法?
问题原因分析
你遇到的编译错误核心是C#泛型集合的不变性:虽然Car和Plane都继承自Vehicle,但List<Car>并不是List<Vehicle>的子类——List<T>是**不变(invariant)**的泛型类型,它不支持将派生类集合直接赋值给基类集合的引用。
而IEnumerable<out T>是**协变(covariant)**的(注意out关键字),它允许将IEnumerable<Car>隐式转换为IEnumerable<Vehicle>,这也是我们解决问题的关键。
解决方案
我给你推荐三种简洁的解决方式,按推荐程度排序:
1. 将方法参数改为IEnumerable<Vehicle>
这是最省心的方案,因为你的方法只需要遍历集合,不需要修改集合(比如添加/删除元素),IEnumerable<T>完全能满足需求,同时它支持协变:
namespace Rextester { abstract class Vehicle{ public int Speed; } class Car: Vehicle{ public string VIN; } class Plane : Vehicle{ public int altitude; } public class Program { public static void Main(string[] args) { var cars= new List<Car>(); var planes = new List<Plane>(); List<Vehicle> movingCars= getMovingVehicles(cars); List<Vehicle> movingPlanes=getMovingVehicles(planes); } // 修改参数为IEnumerable<Vehicle> static List<Vehicle> getMovingVehicles(IEnumerable<Vehicle> vehicles){ List<Vehicle> movingVehicles=new List<Vehicle>(); foreach( Vehicle v in vehicles){ if(v.Speed>0) movingVehicles.Add(v); } return movingVehicles; } } }
2. 使用泛型方法(保留List参数,同时支持派生类)
如果你必须保留List<T>作为参数,可以写一个带泛型约束的方法,这样既能接收任意Vehicle派生类的List,还能灵活控制返回类型:
namespace Rextester { abstract class Vehicle{ public int Speed; } class Car: Vehicle{ public string VIN; } class Plane : Vehicle{ public int altitude; } public class Program { public static void Main(string[] args) { var cars= new List<Car>(); var planes = new List<Plane>(); // 可以返回List<Car>或者List<Vehicle>,按需选择 List<Car> movingCars= getMovingVehicles(cars); List<Plane> movingPlanes=getMovingVehicles(planes); // 或者转成基类集合 List<Vehicle> movingCarsAsVehicle= getMovingVehicles(cars); } // 泛型方法,约束T必须是Vehicle的子类 static List<T> getMovingVehicles<T>(List<T> vehicles) where T : Vehicle{ List<T> movingVehicles=new List<T>(); foreach( T v in vehicles){ if(v.Speed>0) movingVehicles.Add(v); } return movingVehicles; } } }
这种方法的好处是返回的集合类型和输入一致,不需要额外的类型转换,更符合类型安全的要求。
3. 调用时显式转换(不推荐,仅作补充)
如果你不想修改原方法,也可以在调用时把List<Car>转成List<Vehicle>,但这种方式需要额外的转换操作,不够优雅:
// 在Main方法中修改调用代码 List<Vehicle> movingCars= getMovingVehicles(cars.Cast<Vehicle>().ToList()); List<Vehicle> movingPlanes=getMovingVehicles(planes.Cast<Vehicle>().ToList());
内容的提问来源于stack exchange,提问作者Jakub Mosakowski
相关产品推荐
相关产品推荐

