为什么IList <childt>无法转换为IList <parentt>?</parent> </child>

时间:2013-09-18 09:16:41

标签: c# inheritance

我有两节课: ParentChild:Parent

当我做下一个时:

IMyRepository<Child> _childRepository=new MyRepository<Child>();
IMyRepository<Parent> _repository=childRepository;

我收到错误“”不能将源类型转换为目标类型“。 请告诉我为什么这段代码不起作用。

5 个答案:

答案 0 :(得分:4)

因为,您可以插入new AnotherDifferentChild() - 这在IList<Child>中可能不存在。如果您想了解有关详细信息的更多信息,请查看有关协方差 Contravariance Invariance 的文章。

如果要创建新列表,保留类型为Parent的引用,可以使用LINQ中的Cast<T>()方法:

IList<Parent> parentList = childList.Cast<Parent>().ToList();

答案 1 :(得分:1)

我不太擅长投射,但我不认为泛型会对父类型进行隐式转换。

但添加

childRepository.Cast<Parent>()

尽管您可能需要为IEnumerable<T>制作新版IMyRepository<T>

的扩展程序,但仍然可以实现此目标

答案 2 :(得分:1)

试试这个

List<Parent> listOfParent = new List<Child>().Cast<Parent>().ToList();

或者

List<Parent> listOfParent = new List<Child>().ConvertAll(x => (Parent)x);

答案 3 :(得分:1)

如果我们使用略有不同的类名,那么您不允许这样做的原因将会变得清晰。

考虑这个类层次结构:

public class Mammal
{
}

public class Cat: Mammal
{
    public void Meow(){}
}

现在假设您有以下列表:

IList<Cat> cats = new List<Cat>{ new Cat() }

cats[0].Meow(); // All is fine.

现在我们假设您可以将cats分配给IList<Mammal>

IList<Mammal> mammals = cats; // Not allowed, but pretend it is.

mammals.Add(new Mammal()); 

// Because 'mammals' is referencing 'cats', then adding an element to 'mammals'
// will affect 'cats' too - they are both the same list.
// So now cats has two elements; the first is a Cat and the second is a Mammal.

// So now what happens when we do this?

cats[1].Meow(); // Ask a Mammal to Meow(). Ooopsie!

答案 4 :(得分:0)

想象一下,如果你能做到这一点,会发生什么。您可以编写如下代码:

    IList<Child> children = new List<Child>();
    IList<Parent> parents = children;
    parents.Add(new Parent());

请注意,parents仍然是与children相同的对象的引用,但是我们设法将Child的实例添加到IList<Child> }!

正如另一个答案所提到的,这与协方差问题有关(与称为Category Theory的数学领域密切相关 - 如果你有机会看到它,那就很有趣)。

基本上,如果我们写T-> S,对于 S多态到T 的两种类型,比如Parent -> Child,那么泛型是协变如果它保留了这种关系。例如,IEnumerable是一个协变因为IEnumerable<Object> -> IEnumerable<String>。编译器知道这一点,因为您可以将IEnumerable<String>强制转换为IEnumerable<Object>