逻辑及其在Collections中的应用。泛型和继承
一切都从对象继承。这是继承的基础。一切都可以隐式地继承继承树,即。
object me = new Person();
因此,遵循此逻辑结论,一群人也将是一组对象:
List<Person> people = new List<Person>(); people.Add(me); people.Add(you); List<object> things = people; // Ooops.
除了那行不通之外,.NET设计人员或者忽略了这一点,或者有一个原因,我不确定是哪个原因。至少有一次我遇到了本该有用的情况,但最终不得不使用讨厌的hack(将List子类化只是为了实现强制转换运算符)。
问题是这样的:这种行为是否有原因?是否有更简单的解决方案来获得所需的行为?
作为记录,我相信我想要这种行为的情况是一种通用的打印函数,该函数通过调用ToString()并很好地格式化字符串来显示对象列表。
解决方案
我们可以使用linq进行投射:
IEnumerable<Person> oldList = someIenumarable; IEnumerable<object> newList = oldlist.Cast<object>()
好的,每个在.net中使用泛型的人都必须在某一点或者另一点遇到此问题。
是的,从直觉上讲,它应该起作用。不,在当前版本的Ccompiler中没有。
埃里克·利珀特(Eric Lippert)对这个问题有一个很好的解释(它有11个部分,可能会引起注意,但值得一读)。看这里。
编辑:
挖掘出另一个相关的链接,此链接讨论java如何处理此链接。看这里
使用linq扩展方法,我们可以执行
IEnumerable<object> things = people.Cast<object>(); List<object> things = people.Cast<object>().ToList();
否则,由于我们要严格键入列表,因此不允许进行隐式转换。
乍一看,这没有直观的意义。但是,确实如此。看下面的代码:
List<Person> people = new List<Person>(); List<object> things = people; // this is not allowed // ... Mouse gerald = new Mouse(); things.add(gerald);
现在我们突然有了一个" Person"对象的" List" ...里面有一个" Mouse"!
这解释了为什么即使将" S"是" T"的超类型,也不允许将" A <T>"类型的对象分配给" A <S>"类型的变量。
linq解决方法是一个不错的选择。由于我们正在使用类型对象,因此另一个解决方法是将列表作为IEnumerable(而不是通用版本)传递。
编辑:C4(当前为beta)在IEnumerable中支持协变类型参数。虽然我们将无法直接分配给List <object>,但是可以将列表传递给期望IEnumerable <object>的方法。
尽管我们尝试做的事情确实符合逻辑,但实际上它是许多语言本身不支持的功能。这就是所谓的co / contra差异,它与编译器何时,如何将对象从一件事隐式转换为nother有关。值得庆幸的是,C4.0将为Carena带来协方差和自变量,这样的隐式强制转换应该是可能的。
有关此内容的详细说明,以下Channel9视频应该会有所帮助:
http://channel9.msdn.com/shows/Going+Deep/Inside-C-40-dynamic-type-optional-parameters-more-COM-friendly/