我有以下类层次结构:
public abstract class BaseData
{
//some properties
}
public class CoData : BaseData
{
//some properties
}
我正在使用一个需要返回类型为List<BaseData>
的方法。在该方法中,我可以访问List<CoData>
public List<BaseData> Save()
{
List<CoData> listCoData = GetData();
return listCoData;
}
如果我理解正确,我可以从CoData
转发到BaseData
。但是,当我有一个列表时,即使我明确地试图进行类型转换,它也会出错。
错误:
Error 118 Cannot implicitly convert type 'System.Collections.Generic.List<CoData>' to System.Collections.Generic.List<BaseData>'
修改
mquander的转换方法似乎在3.0中适用于我
是否也以同样的方式完成了向下转换?来自
即,我可以这样做 - List<CoData> listCoData = listBaseData.Cast<BaseData>().ToList();
答案 0 :(得分:10)
是;欢迎来到差异。最终,不是 BaseData
的列表 - 例如,如果你有另一个子类,List<BaseData>
会(在编译时)让你.Add
它...但运行时类型不会让你。编译器阻止你犯错。
在某些情况下,泛型可以在这里提供帮助......我在this blog entry结尾讨论这个问题。请注意,.NET 4.0差异不适用于列表。
答案 1 :(得分:7)
这对于您的集合的参数称为“协方差”,而C#现在不支持这种协方差。在C#4.0中,用户定义的类型和一些内置类型(如IEnumerable<T>
)将支持此功能。
与此同时,你可以通过创建一个带有显式演员的新枚举来解决这个问题(你可能想考虑将你的东西的返回类型更改为IEnumerable<T>
,这样你就不必实际不断烹饪新的收藏品:)
public List<BaseData> Save()
{
List<CoData> listCoData = GetData();
return listCoData.Cast<BaseData>().ToList();
}
根据GetData的工作原理,您可能还会考虑这样的结构:
public List<T> Save<T>() where T : BaseData
{
return listCoData = GetData<T>();
}
编辑:实际上,正如Marc和其他人无疑会指出的那样,List<T>
不能像这样协变,因为你可以添加成员,如果它是破坏类型安全的话。但是,如果您发回了IEnumerable<T>
,则可以在此处使用协方差。
编辑2 :回答您的其他问题:
我可以这样做吗?
List<CoData> listCoData = listBaseData.Cast<BaseData>().ToList();
没有。 listBaseData.Cast<BaseData>().ToList();
返回List<BaseData>
类型的对象,该对象无法直接转换为List<CoData>
。这就是为什么我们必须首先去做这个努力。
答案 2 :(得分:2)
mquander解决方案的另一个变体是实现Save as:
public List<BaseData> Save()
{
List<CoData> listCoData = GetData();
return listCoData.ConvertAll<BaseData>(
delegate(CoData c) { return c as BaseData; });
}
这将允许您在匿名委托中进行一些额外的处理,而不仅仅是强制转换。
要记住的重要一点是,当CoData继承自BaseData时,List不会从List继承。
答案 3 :(得分:1)
您必须等到C#4.0才能使用generic covariance。