我使用.NET 2.0在C#中编程,我不明白为什么下面的转换导致空引用。
如果您有IList< IChild>,为什么不能将它转换为IList< IParent> 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);
}
}
}
答案 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
添加到实际上是整数列表中。