【问题标题】:Why can't List<parent> = List<child>?为什么不能 List<parent> = List<child>?
【发布时间】:2010-11-13 05:50:04
【问题描述】:

为什么下面的代码不起作用?

class parent {}
class kid:parent {}

List<parent> parents=new List<kid>;

这对我来说似乎很明显。这是怎么回事?

【问题讨论】:

  • 是的,我认为这个问题是个骗子,只是我不知道该搜索什么。
  • 长颈鹿列表不是动物列表。为什么?因为您可以将老虎添加到动物列表中,但不能添加到长颈鹿列表中。由于这两种类型具有不同的合法操作,因此您不能将一种转换为另一种。

标签: c# .net oop inheritance


【解决方案1】:

C# 目前不支持covariance

在 .NET 4.0 中它是 coming,但在接口和委托上。

Eric Lippert 不久前在他的博客上有一个非常好的seriesVisual Studio Magazine 在最近的 article 中也涵盖了它。

【讨论】:

  • +1:里氏替换原则的经典失败。提议的孩子通常不能替代提议的父母,因此继承可能是错误的。
【解决方案2】:

您正在寻找的特征称为协方差。在 4.0 版之前,C# 中不支持它,然后仅在接口和委托上。

关于该主题的一些链接

【讨论】:

    【解决方案3】:

    如前所述,C# 目前不支持此功能。在 Java 中,数组是协变的,它可能会导致一些问题。考虑您的示例,实际列表应该是“孩子”列表,这意味着其中的所有对象都应该是“孩子”(或“孙子”)。但是,如果您用来访问列表的引用是“父”列表,那么您可以在列表中插入一个“父”,这显然不应该发生。

    【讨论】:

      【解决方案4】:

      除了在 C# 4.0 之前的版本中缺乏泛型方差支持之外,List 是可变的,因此不能安全地协变。考虑一下:

      void AddOne<T>(List<T> arg) where T : new()
      {
          arg.Add(new T());
      }
      
      void Whoops()
      {
          List<parent> contradiction = new List<kid>();
          AddOne(contradiction);  // what should this do?
      }
      

      这会尝试将 Parent 添加到通过 List 引用引用的 List 中,这是不安全的。运行时允许数组协变,但在突变时进行类型检查,如果新元素不可分配给数组的运行时元素类型,则会引发异常。

      【讨论】:

        【解决方案5】:

        如果您知道 List&lt;Parent&gt; 包含 List&lt;child&gt; 您可以使用扩展方法来“转换”,(实际上只需将 ARE 类型为 child 的 Parent 并将它们返回到列表中。例如:

          public static List<T> Convert<T, T2>(this List<T2> input) {
              return input.OfType<T>().ToList();
            }
        

        我不确定这是否对您有帮助,但我的 2 美分值得!我经常使用它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-11
          • 1970-01-01
          • 2019-07-10
          • 1970-01-01
          • 2015-10-14
          • 2021-07-11
          相关资源
          最近更新 更多