list.ToArray vs list
本文关键字:list vs ToArray | 更新日期: 2023-09-27 18:02:28
我注意到一些奇怪的事情,有可能我错了。
我有接口IA和类A:
interface IA { .... }
class A : IA { .... }
在另一类中,我有这个:
private IList<A> AList;
public IList<IA> {
get { return AList; }
}
但是我得到编译错误。但是如果我改成:
public IList<IA> {
get { return AList.ToArray(); }
}
一切都好。
为什么?
为什么不行
private IList<A> AList;
public IList<IA> { get { return AList; } }
将属性暴露为IList<IA>
将允许您尝试将class B : IA
添加到列表中,但底层列表实际上是 IList<A>
, B
不是A
,因此这将在您的脸上爆炸。因此,它是不允许的。
为什么工作:
public IList<IA> { get { return AList.ToArray(); } }
数组方差被打破。您可以将列表作为数组返回,如果您尝试Add
操作(或者尝试用A
类型以外的对象替换给定索引处的对象),它仍然会在运行时出现问题,但它在编译时是合法的。这个差异的另一个例子:
string[] array = new string[10];
object[] objs = array; // legal
objs[0] = new Foo(); // will bite you at runtime
From comments:
那你建议用什么呢?我怎样才能使物业申报表有效对象?我怎样才能使返回值只读?
如果消费者只需要迭代序列,而不是随机的,索引访问它,你可以公开属性作为IEnumerable<IA>
。
public IEnumerable<IA> TheList
{
get { return AList.Select(a => a); }
}
(Select
实际上在技术上并不需要,但是使用它将阻止消费者将结果强制转换为其真正的底层List<>
类型)。如果消费者决定他们想要一个列表或数组,他们可以自由地调用ToList()
或ToArray()
,并且无论他们对它做什么(就添加,删除,替换项而言)都不会影响列表。(对项目属性的更改将是可见的。)同样,您也可以自己以一种安全的方式公开IList<IA>
集合
public IList<IA> TheList
{
get { return AList.ToList<IA>(); }
}
同样,这将返回列表的副本,因此对它的任何更改都不会影响底层列表。
因为本地数组是坏的。这段代码很糟糕,你不应该这样做,c#的设计者迫切希望他们能撤销它。
数组是协变的,而列表不是。