【问题标题】:Logic and its application to Collections.Generic and inheritance逻辑及其在 Collections.Generic 和继承中的应用
【发布时间】:2010-09-11 17:27:05
【问题描述】:

一切都继承自对象。这是继承的基础。一切都可以隐式地投射到继承树上,即。

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() 并很好地格式化字符串来显示对象列表。

【问题讨论】:

    标签: .net inheritance collections


    【解决方案1】:

    虽然您尝试执行的操作确实符合逻辑,但它实际上是许多语言本身不支持的功能。这就是所谓的 co/contra 方差,它与编译器何时以及如何将对象从一件事隐式转换为另一件事有关。值得庆幸的是,C# 4.0 将为 C# 领域带来协变和逆变,这样的隐式转换应该是可能的。

    关于这个的详细解释,下面的 Channel9 视频应该会有所帮助:

    http://channel9.msdn.com/shows/Going+Deep/Inside-C-40-dynamic-type-optional-parameters-more-COM-friendly/

    【讨论】:

      【解决方案2】:

      linq 解决方法是一个很好的解决方法。由于您使用的是类型对象,因此另一种解决方法是将列表作为 IEnumerable(不是通用版本)传递。

      编辑:C# 4(当前为测试版)支持 IEnumerable 中的协变类型参数。虽然您无法直接分配给 List,但您可以将列表传递给需要 IEnumerable 的方法。

      【讨论】:

        【解决方案3】:

        好的,每个在 .net 中使用过泛型的人一定都曾遇到过这种情况。

        是的,直觉上它应该可以工作。不,在当前版本的 C# 编译器中没有。

        Eric Lippert 对这个问题有很好的解释(它分为 11 个部分或其他内容,可能会让您在某些地方弯曲,但非常值得一读)。见here

        编辑:

        挖出了另一个相关链接,这个链接讨论了 java 是如何处理这个问题的。见here

        【讨论】:

          【解决方案4】:

          乍一看,这并不直观。但确实如此。看这段代码:

          List<Person> people = new List<Person>();
          List<object> things = people; // this is not allowed
          // ...
          Mouse gerald = new Mouse();
          things.add(gerald);
          

          现在我们突然有一个ListPerson 对象...里面有一个Mouse

          这解释了为什么不允许将A&lt;T&gt; 类型的对象分配给A&lt;S&gt; 类型的变量,即使ST 的超类型。

          【讨论】:

          • 同意,但是拥有与可以指定 'T 的 java 泛型相同的设施不是很好吗?超级MyClass'?
          • 您总是可以通过将转换列表标记为只读来解决此问题,但您的观点很好。
          • 然后尝试接受答案中提到的 Eric Lippert 的解释。它涉及所有细节。
          【解决方案5】:

          你可以使用 linq 扩展方法

          IEnumerable<object> things = people.Cast<object>();
          List<object> things = people.Cast<object>().ToList();
          

          否则,由于您是强类型列表,因此不允许隐式转换。

          【讨论】:

            【解决方案6】:

            你可以使用 linq 来投射它:

            IEnumerable<Person> oldList = someIenumarable;
            IEnumerable<object> newList = oldlist.Cast<object>()
            

            【讨论】:

            • 请注意,这是一个迭代转换,会影响性能。不要将 LINQ Cast 方法与本机 C# 转换混淆...两者是不同的。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-07-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-03-27
            • 1970-01-01
            相关资源
            最近更新 更多