我已经离开遗产一段时间了,需要一点帮助。
我有一个抽象基类Chief
。有两个继承类Ship
和Vehicle
,它们通过Chief
共享多个属性。
我有一个使用这些常用属性的方法:
public static void AssignRandomProperties(PSetList routeSettings, List<Chief> theChiefs)
但是当我尝试传递
时List<Ship>
或
List<Vehicle>
我被告知他们无法转换。这是一个示例方法调用:
ChiefRouteRandomizer.AssignRandomProperties(s.Route, theVehicles);
我当然假设List<Vehicle>
在作为List<Chief>
的参数传递时会被视为AssignRandomProperties
,但显然不是。列表是否需要先转换为List<Chief>
?如果是这样,怎么样?
答案 0 :(得分:8)
首先解释一下。您无法将List<Vehicle>
转换为List<Chief>
,因为Add方法将具有签名void List<Chief>.Add(Chief item)
,您可以将Chief
类的实例存储在已声明的列表中只持有Vehicle
。这会破坏类型系统;因此不允许。
解决这个问题的最简单方法是传入theVehicles.ToList<Chief>()
。但是,这将创建一个新列表。这有两个含义:(1)你会通过复制列表浪费内存,(2)如果方法要改变列表本身(添加/删除项目或用其他成员替换成员),你将看不到这些更改在theVehicles
列表中。 (如果列表中的引用指向的对象是唯一被修改的对象,则这不是问题。)
如果您可以控制AssignRandomProperties方法,请考虑使用此签名:
public static void AssignRandomProperties<T>(
PSetList routeSettings,
IList<T> theChiefs) where T : Chief
{
...
}
答案 1 :(得分:2)
看看这个:
List<Ship> ships = new List<Ship>();
List<Chief> asChiefs = (List<Chief>)ships;
asChiefs.Add(new Car());
// so what, now ships[0] is a Car?
这就是为什么你不能把船只列表作为酋长名单。如果你想进一步了解这一点,可以说List不是covariant(也不是逆变)。
现在,您的AssignRandomProperties方法是否真的需要List<T>
?如果您所做的只是迭代它,那么您不需要List<T>
,您可以使用IEnumerable<T>
实现的List<T>
。这里的好处是IEnumerable<T>
没有提供修改列表的方法,所以它是协变的(从.NET 4开始)。这意味着你可以这样做:
IEnumerable<Chief> chiefs = ships;
答案 2 :(得分:0)
这是我最喜欢的技巧
public static void AssignRandomProperties<T>(PSetList routeSettings, List<T> theChiefs)
where T : Chief
然后,你打电话如下
AssignRandomProperties<Vehicle>(s.Route, theVehicles);
答案 3 :(得分:0)
假设您的方法体看起来像这样:
public static void AssignRandomProperties(PSetList routeSettings, List<Chief> theChiefs)
{
foreach (var chief in theChiefs)
{
//assign some properties
}
}
并且假设您使用引入协方差和逆变的C#4.0,您可以这样做,避免使用已建议的通用解决方案:
public static void AssignRandomProperties(PSetList routeSettings, IEnumerable<Chief> theChiefs)
{
foreach (var chief in theChiefs)
{
//assign some properties
}
}