为什么IList 的功能少于List ?
要使用如ConvertAll()
这样的强大function,我必须将IList
转换为List
,这很痛苦。
请注意, List<>
是具有实际存储的IList<>
的实现,即它在后台保存一个数组。 通常, IList<>
可以是其他东西的代理。 在db4o和linq to sql中,您的IList<>
可以“指向查询”,即访问列表将触发数据库操作。
这样,你就可以执行myList.Skip(600).Take(20);
执行分页,只有在此步骤中才会执行实际查询。 包含一百万个条目的List<>
将是巨大的,而可能有IList<>
s具有巨大的Count
,但是不要占用大量内存 – 只要您不访问这些元素。
ConvertAll
将要求实例化每个对象,因此操作成本很高。 因此,最好使操作显式化并强制您检索接口的特定实现。 显然,转换要求所有对象都要实例化,所以懒惰地做这件事没有任何好处。
为什么不使用IEnumerable
而不是List
? 由于IList
inheritance了IEnumerable
。 在SO上看到这个问题 。
因为接口定义了单个行为,而类可以实现多个不同的接口,并且还具有接口未指定的function。
如果需要List
类的function,请不要使用IList
引用。 从头开始使用List
引用。
仅仅因为IList(T)
是一个接口,而List(T)
是.net bcl中为了具有索引器function而实现IList(T)
的几个类之一。 并非所有实现IList(T)
都需要ConvertAll()
方法,该方法用于将某个generics类型的generics列表转换为另一个类型。
IList
接口旨在实现广泛的实现。 通过省略便捷方法,这意味着实现界面的工作量减少,编写错误的机会也减少。
幸运的是,LINQ方面通过“扩展方法”function实现了这一步并添加了许多有用的方法。 Select
和Cast
特别适用于转换目的。 确保您以.NET Framework 3.5为目标,引用System.Core
程序集,并using System.Linq;
看见了。
接口中的每个方法或属性定义都会强制接口的每个实现为其提供代码。 如果一个接口是由全世界一万个类实现的,那么向接口添加一个只需要执行一行可执行代码的方法就会增加所有这些实现所需的代码总量至少四万行(假设正常的白色) – 间距约定)。 相比之下,向类添加辅助方法对实现它的接口没有任何要求。
顺便说一句,.net的一个主要愿望列表项是接口可以通过静态方法将成员声明为具有默认实现的方式(例如,包含成员string Boz(int param)
IFoo
可以指定如果代码对于一个寻求实现IFoo
的类不包含该成员,编译器或运行时应该自动生成方法string IFoo.Boz(int param) { return IFoo_Helpers.Boz(this, param);}
。如此从2.0版本的.net中存在一个方法工具,它现在可能已经保存了数十万甚至数百万行代码,只需要让IEnumerable
包含一个默认实现IEnumerator IEnumerable.GetEnumerator() {return IEnumerable_Helpers
,后一种方法只是static IEnumerable GetEnumerator(IEnumerable
。这样的function会让接口提供更多function对他们的消费者没有任何影响 重新开始他们的实施者。 此外,与必须在调用站点静态绑定的扩展方法不同,此类接口方法将在实现处绑定,因此允许在适当时使用特定于实现的覆盖(例如,如果IEnumerable
提供ToList
方法, List
可以定义一个快速实现,它创建一个新的List
预先初始化为适当的大小,并使用Array.Copy
来填充它, IEnumerable
实现将返回无限序列可能会抛出exception(而不是吞噬他们可以得到的所有内存),但是大多数实现不必对该方法做任何事情 – 他们可以简单地遵循默认的通用辅助函数,该函数将项目枚举为新的List
让它根据需要增长。