以下代码抛出InvalidCastException。
public static MachineProductCollection MachineProductsForMachine(
MachineProductCollection MachineProductList, int MachineID)
{
return (MachineProductCollection)
MachineProductList.FindAll(c => c.MachineID == MachineID);
}
这让我感到惊讶,因为MachineProductCollection只是一个通用的MachineProducts列表,正是FindAll()应该返回的。这是完整的MachineProductCollection源代码。您将注意到它只是List的包装器。
[Serializable]
public partial class MachineProductCollection :
List<MachineProduct>
{
public MachineProductCollection() { }
}
我使用了以下内容,它基本上循环遍历FindAll()类型为List的结果,并将每个项目添加到我的MachineProductCollection中。显然,我不喜欢所需的迭代。
public static MachineProductCollection
MachineProductForMachine(MachineProductCollection
MachineProductList, int MachineID)
{
MachineProductCollection result =
new MachineProductCollection();
foreach (MachineProduct machineProduct in
MachineProductList.FindAll(c => c.MachineID == MachineID))
{
result.Add(machineProduct);
}
return result;
}
文档说明在显式引用转换期间发生故障时抛出InvalidCastException。参考转化是从一种参考类型到另一种参考类型的转换。虽然它们可能会更改引用的类型,但它们永远不会更改转换目标的类型或值。将对象从一种类型转换为另一种类型是此异常的常见原因。
考虑List是MachineProductCollection的基础,这真的应该是InvalidCastException吗?
答案 0 :(得分:5)
是的,无效的强制转换异常是正确的。您可以从派生类自由地转换为基类,但是您不能盲目地从基类转换为派生类,除非该对象确实是派生类的实例。这是你不能这样做的原因:
object obj = new object();
string str = (string) obj;
右? object
是string
的基础,您无法从object
自由地投射到string
。另一方面,这将起作用,因为obj
确实是一个字符串:
object obj = "foo";
string str = (string) obj;
答案 1 :(得分:1)
您收到InvalidCastException
,因为List<MachineProduct>
不一定是MachineProductCollection
,即使反过来显然也是如此。
返回实际MachineProductCollection
的最简单的解决方案是使用List<T>
的序列构造函数:
public static MachineProductCollection
MachineProductForMachine(MachineProductCollection MachineProductList, int MachineID)
{
List<MachineProduct> found =
MachineProductList.FindAll(c => c.MachineID == MachineID))
return new MachineProductCollection(found);
}
但是,由于您正在使用lambda表达式,我猜您可以访问LINQ(通过.NET 3.5或LINQ Bridge),这意味着您可以使用Where
扩展方法跳过中间清单:
public static MachineProductCollection
MachineProductForMachine(MachineProductCollection MachineProductList, int MachineID)
{
IEnumerable<MachineProduct> found =
MachineProductList.Where(c => c.MachineID == MachineID))
return new MachineProductCollection(found);
}
那就是说,你最好只返回IEnumerable<MachineProduct>
而不是创建自己的集合类型。除非您计划为MachineProductCollection
添加特殊逻辑,否则这可能会让您的生活更轻松。在这种情况下,您可以始终只针对IEnumerable<MachineProduct>
编写扩展方法来提供该逻辑。只需要考虑一些事情......