逻辑及其在Collections中的应用。泛型和继承

时间:2020-03-06 14:29:57  来源:igfitidea点击:

一切都从对象继承。这是继承的基础。一切都可以隐式地继承继承树,即。

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/