为什么你不能从IList <iparent>转换为IList <ichild>,其中IChild实现IParent </ichild> </iparent>

时间:2009-11-10 20:23:26

标签: c# generics inheritance list interface

  

可能重复:
  IList<Type> to IList<BaseType>

我使用.NET 2.0在C#中编程,我不明白为什么下面的转换导致空引用。

如果您有IList&lt; IChild&gt;,为什么不能将它转换为IList&lt; IParent&gt; IChild实现IParent。

using System.Collections.Generic;

namespace InterfaceTest
{
    public interface IParent
    {
    }

    public interface IChild : IParent
    {
    }

    public abstract class Parent : IParent
    {
    }

    public sealed class Child : Parent, IChild
    {
    }

    public sealed class Container
    {
        public IList<IChild> ChildInterfaceList
        {
            get;
            set;
        }

        public Container()
        {
            ChildInterfaceList = new List<IChild>();
        }
    }

    class Program
    {
    static void Main(string[] args)
    {
            Container container = new Container();

            var childInterfaceList = container.ChildInterfaceList;

            System.Diagnostics.Debug.Assert(childInterfaceList != null);

            var parentInterfaceList = container.ChildInterfaceList as IList<IParent>;

            //I don't expect parentInterfaceList to be null, but it is
            System.Diagnostics.Debug.Assert(parentInterfaceList != null);
        }
    }
}

2 个答案:

答案 0 :(得分:3)

C#mutable集合不支持集合元素类型的差异。考虑如果你这样做将会发生什么:

IList<IChild> kids = new List<IChild> {
    new Egg("Shelly"), new Egg("Egbert"), new Egg("Yoko")
};

var parents = kids as IList<IParent>;

parents.Add(new Sloth("Sid")); // what would happen here?

如果转换成功,parents的运行时类型仍然是List<IChild>,它将不接受未实现IChild的内容,并且必须抛出异常。

可接受的转换是:

using System.Linq;
var parents = kids.Cast<IParent>().ToList();

会创建原始列表的副本,但List<IParent>为其运行时类型。

C#4.0支持通用方差,但不能安全地将可变集合变为变体。只有像IEnumerable这样的纯只读接口可以安全地进行协变,纯粹的只写接口(有没有?)可以安全地做成逆变。

答案 1 :(得分:0)

这是一个常见的陷阱。

考虑这个简单的解释 - 例如:

.NET中的所有东西都继承自Object,对吧?那么,让我们假设你想要的东西是可能的......

List<int> ints = new List<int>();
List<object> objects = ints as List<object>;
objects.Add("Hello there!");

您刚刚尝试将string添加到实际上是整数列表中。