为什么IList<>功能少于List<&gt ;?

时间:2010-03-13 14:05:30

标签: c# .net list generics

要使用ConvertAll()这样的强大功能,我必须将IList转换为List,这很痛苦。

6 个答案:

答案 0 :(得分:17)

请注意List<>是具有实际存储空间的IList<>的实现,即它在后台保存数组。通常,IList<>可以代替其他内容。在db4o和linq to sql中,您的IList<>可以“指向查询”,即访问列表将触发数据库操作。

这样,您可以执行myList.Skip(600).Take(20);来执行分页,只有在此步骤中才能执行实际查询。包含一百万个条目的List<>将是巨大的,而可能IList<>有一个巨大的Count,但是不要吃大量的内存 - 只要你不要不能访问元素。

ConvertAll将要求实例化每个对象,因此这是一项代价高昂的操作。因此,最好使操作显式化并强制您检索接口的特定实现。显然,转换要求所有对象都要实例化,所以懒惰地做这件事没有任何好处。

答案 1 :(得分:11)

为什么不使用IEnumerable<T>.Select代替List<T>.ConvertAll?由于IList继承了IEnumerable。在SO上看到这个question

答案 2 :(得分:4)

因为接口定义了单个行为,而类可以实现多个不同的接口,并且还具有接口未指定的功能。

如果您想要List<T>类的功能,请不要使用IList<T>引用。从头开始使用List<T>引用。

答案 3 :(得分:2)

仅仅因为IList(T)是一个接口,而List(T)是.net bcl中为了拥有索引器功能而实现IList(T)的几个类之一。并非所有实现IList(T)的类都需要ConvertAll()方法,该方法用于将某种泛型类型的通用列表转换为另一种类型。

答案 4 :(得分:1)

IList界面旨在广泛实施。通过省略便捷方法,这意味着实现界面的工作量减少,编写错误的机会减少。

幸运的是,LINQ方面通过“扩展方法”功能实现了这一步并添加了许多有用的方法。 SelectCast对转换目的特别有用。确保以.NET Framework 3.5为目标,引用System.Core程序集,并using System.Linq;进行查看。

答案 5 :(得分:0)

接口中的每个方法或属性定义都会强制接口的每个实现为其提供代码。如果一个接口是由全世界一万个类实现的,那么向接口添加一个只需要执行一行可执行代码的方法就会增加所有这些实现所需的代码总量至少四万行(假设正常的白色) - 间距约定)。相比之下,向类添加辅助方法对实现它的接口没有任何要求。

顺便提一下,.net的一个主要愿望清单项是接口可以通过静态方法将成员声明为具有默认实现的方式(例如IFoo,其中包含成员string Boz(int param)可以指定如果寻求实现IFoo的类的代码不包含该成员,则编译器或运行时应该自动生成方法string IFoo.Boz(int param) { return IFoo_Helpers.Boz(this, param);}。如果存在这样的方法工具从版本2.0开始,它可能已经保存了数十万甚至数百万行代码,只需要IEnumerable<T>包含默认实现IEnumerator IEnumerable.GetEnumerator() {return IEnumerable_Helpers<T>.GetEnumerator(this);},后一种方法就是static IEnumerable GetEnumerator(IEnumerable<T> it) {return it.GetEnumerator();}。这样的功能可以让接口为其消费者提供更多功能,而不会对其实施者施加更多的工作。此外,与呼叫站点必须静态绑定的扩展方法不同,此类接口方法会受限于实现,因此允许在app时使用特定于实现的覆盖ropriate(例如,如果IEnumerable<T>提供ToList方法,List<T>可以定义一个快速实现,创建一个新的List<T>预先初始化为适当的大小并使用{{ 1}}填充它,Array.Copy的实现将返回无限序列可能会抛出异常(而不是吞噬他们可能得到的所有内存),但大多数实现不必对该方法做任何事情 - 他们可以简单地遵循默认的通用辅助函数,该函数将项目枚举为新的IEnumerable<T>并让它根据需要增长。