给定接口IQuestion
和该接口的实现AMQuestion
,假设以下示例:
Listtyped = new List (); IList nonTyped = typed;
正如预期的那样,这个例子产生一个编译错误,说明两者的类型不同.但它表明存在明确的转换.所以我把它改成这样:
Listtyped = new List (); IList nonTyped = typed as IList ;
然后编译,但在运行时,nonTyped
始终为空.如果有人可以解释两件事:
为什么这不起作用.
我怎样才能达到预期的效果.
这将不胜感激.谢谢!
为什么它不工作:as
返回null
如果值的动态类型不能被强制转换为目标类型,并且List<AMQuestion>
不能被强制转换为IList<IQuestion>
.
但为什么不能呢?好吧,检查一下:
List<AMQuestion> typed = new List<AMQuestion>(); IList<IQuestion> nonTyped = typed as IList<IQuestion>; nonTyped.Add(new OTQuestion()); AMQuestion whaaaat = typed[0];
IList<IQuestion>
说"你可以添加任何IQuestion
给我".但这是一个它无法保留的承诺,如果它是一个List<AMQuestion>
.
现在,如果您不想添加任何内容,只需将其视为IQuestion
兼容事物的集合,那么最好的办法就是将其转换为IReadOnlyList<IQuestion>
with List.AsReadOnly
.由于只读列表不能添加奇怪的内容,因此可以正确地进行转换.
这样的事实AMQuestion
实现了IQuestion
接口并没有转化为List<AMQuestion>
从派生List<IQuestion>
.
因为此演员表是非法的,您的as
运营商会返回null
.
您必须单独投射每个项目:
IList<IQuestion> nonTyped = typed.Cast<IQuestion>().ToList();
关于您的评论,请考虑以下代码,以及常见的陈词滥调动物示例:
//Lizard and Donkey inherit from Animal List<Lizard> lizards = new List<Lizard> { new Lizard() }; List<Donkey> donkeys = new List<Donkey> { new Donkey() }; List<Animal> animals = lizards as List<Animal>; //let's pretend this doesn't return null animals.Add(new Donkey()); //Reality unravels!
如果我们被允许转换List<Lizard>
为a List<Animal>
,那么我们理论上可以Donkey
在该列表中添加一个新的,这将破坏继承.
问题是List<AMQuestion>
无法强制转换IList<IQuestion>
,因此使用as
运算符无济于事.在这种情况下显式转换意味着转换AMQuestion
为IQuestion
:
IList<IQuestion> nonTyped = typed.Cast<IQuestion>.ToList();
顺便说一句,你的标题中有"协方差"一词.在IList
类型不协变.这正是演员阵容不存在的原因.原因是IList
界面具有T
一些参数和一些返回值,因此既in
不能out
也不能使用T
.(@Sneftel有一个很好的例子来说明为什么不允许这种演员表.)
如果您只需要从列表中读取,则可以使用IEnumerable
:
IEnumerable<IQuestion> = typed;
这将起作用,因为IEnumerable<out T>
已out
定义,因为您无法将其T
作为参数传递.您通常应该在代码中使最弱的"承诺"保持可扩展性.