我有两节课:
Parent
和Child:Parent
。
当我做下一个时:
IMyRepository<Child> _childRepository=new MyRepository<Child>();
IMyRepository<Parent> _repository=childRepository;
我收到错误“”不能将源类型转换为目标类型“。 请告诉我为什么这段代码不起作用。
答案 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>
。