Jos*_*osh 6 .net c# generics casting
有人可以向我解释为什么在.NET 2.0中,如果我有一个接口,IPackable
以及一个实现该接口的类OrderItem
,当我有一个接受a的方法List<IPackable>
,传入一个列表List<OrderItem>
不起作用?
有谁知道我怎么能完成这个功能?
码:
public interface IPackable {
double Weight{ get; }
}
public class OrderItem : IPackable
public List<IShipMethod> GetForShipWeight(List<IPackable> packages) {
double totalWeight = 0;
foreach (IPackable package in packages) {
totalWeight += package.Weight;
}
}
Run Code Online (Sandbox Code Playgroud)
以下代码不起作用.
List<OrderItem> orderItems = new List<OrderItem>();
List<IShipMethod> shipMethods = GetForShipWeight(orderItems);
Run Code Online (Sandbox Code Playgroud)
小智 14
JMD是正确的一半.事实上,说我们能够使用C#4.0转换通用列表是绝对不正确的.确实,C#4.0将支持协方差和逆变,但它只适用于接口和委托,并且会有很多约束.因此,它将无法使用List
.
原因很简单.
如果B是A的子类,我们不能说它List<B>
是A的子类List<A>
.
这就是原因.
List<A>
公开一些协方差方法(返回值)和一些逆变方法(接受一个值作为参数).
例如
List<A>
自曝 Add(A);
List<B>
自曝 Add(B);
如果List<B>
继承自List<A>
...而不是你能做到的List<B>.Add(A);
因此,您将失去仿制药的所有类型安全性.
JMD*_*JMD 11
该功能称为协方差/逆变,将在c#4.0中得到支持.你可以在这里阅读:http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
JMD的答案是正确的.要解决此问题,您可以尝试这样做:
List<IPackable> orderItems = new List<IPackable>();
List<IShipMethod> shipMethods = GetForShipWeight(orderItems);
Run Code Online (Sandbox Code Playgroud)
或者,如果列表必须强类型为OrderItems,那么这个(仅限3.0,抱歉):
List<IShipMethod> shipMethods =
GetForShipWeight(orderItems.Cast<IPackable>().ToList());
Run Code Online (Sandbox Code Playgroud)
也适用于 .NET 3.5 的替代解决方案
List<IShipMethod> shipMethods = GetForShipWeight(orderItems).ConvertAll(sm => sm as IShipMethod);
Run Code Online (Sandbox Code Playgroud)