C# 列表<;T>;或IList<;T>;

C# 列表<;T>;或IList<;T>;,c#,list,generics,C#,List,Generics,有人能解释一下为什么我想在C#中使用IList over List吗 相关问题:如果您通过其他人将使用的库公开您的类,您通常希望通过接口而不是具体实现来公开它。如果您决定稍后更改类的实现以使用不同的具体类,这将有所帮助。在这种情况下,库的用户不需要更新他们的代码,因为接口没有改变 如果您只是在内部使用它,您可能不太在意,使用List也可以。IList是一个接口,因此您可以继承另一个类并仍然实现IList,而继承List阻止您这样做 例如,如果有一个类a,而您的类B继承了它,那么您就不能使用列表

有人能解释一下为什么我想在C#中使用IList over List吗


相关问题:

如果您通过其他人将使用的库公开您的类,您通常希望通过接口而不是具体实现来公开它。如果您决定稍后更改类的实现以使用不同的具体类,这将有所帮助。在这种情况下,库的用户不需要更新他们的代码,因为接口没有改变

如果您只是在内部使用它,您可能不太在意,使用
List
也可以。

IList是一个接口,因此您可以继承另一个类并仍然实现IList,而继承List阻止您这样做

例如,如果有一个类a,而您的类B继承了它,那么您就不能使用列表

class A:B,IList{…}

您可能会这样做,因为定义IList或ICollection会为接口的其他实现打开大门


您可能希望有一个IOrderRepository,它在IList或ICollection中定义订单集合。然后,您可以使用不同类型的实现来提供订单列表,只要它们符合IList或ICollection定义的“规则”。

TDD和OOP的原则通常是编程到接口而不是实现

在这个特定的例子中,由于您主要讨论的是一个语言构造,而不是一个自定义的构造,所以一般来说,这并不重要,但可以说,例如,您发现列表不支持您需要的东西。如果您在应用程序的其余部分使用了IList,您可以使用自己的自定义类扩展列表,并且仍然能够在不重构的情况下传递该列表

这样做的成本很低,为什么不省去以后的头痛呢?这就是接口原则的全部内容。

public void Foo(IList列表)
public void Foo(IList<Bar> list)
{
     // Do Something with the list here.
}
{ //对这里的列表做些什么。 }
在这种情况下,可以传入实现IList接口的任何类。如果改用List,则只能传入一个List实例


IList方式比列表方式松散耦合。

在实现上使用接口最重要的情况是API的参数。如果您的API采用列表参数,那么任何使用它的人都必须使用列表。如果参数类型为IList,则调用者有更多的自由,可以使用您从未听说过的类,这些类在编写代码时可能根本不存在。

List
IList
的具体实现,IList是一个可以与线性数组
T[]相同方式寻址的容器
使用整数索引。当指定
IList
作为方法参数的类型时,只指定需要容器的某些功能

例如,接口规范不强制使用特定的数据结构。
List
的实现在访问、删除和添加元素方面与线性阵列的性能相同。但是,您可以想象一个由链表支持的实现,对于它来说,在末尾添加元素更便宜(固定时间),但随机访问更昂贵。(请注意,.NET
LinkedList
没有实现
IList

本例还告诉您,在某些情况下,您可能需要在参数列表中指定实现,而不是接口:在本例中,每当您需要特定的访问性能特征时。这通常适用于容器的特定实现(
List
documentation:“它使用一个数组实现
IList
通用接口,该数组的大小根据需要动态增加。”)


另外,您可能需要考虑暴露所需的最小功能。例如如果你不需要改变列表的内容,你就应该考虑使用<代码> iQueLabe<代码>,其中<代码> IIST < /代码>扩展。<> > P> <强>接口是一个承诺< /强>(或合同)。


就像承诺一样-越小越好

我想把这个问题转一转,而不是解释为什么应该使用接口而不是具体的实现,而是尝试解释为什么要使用具体的实现而不是接口。如果你不能证明这一点,那么就使用界面。

不太流行的答案是程序员喜欢假装他们的软件将在全世界重复使用,而事实上,大多数项目将由一小部分人维护,无论界面相关的声音片段多么美妙,你都在欺骗自己

。您编写自己的IList来为.NET框架中已有的IList添加任何内容的可能性是如此之小,以至于在理论上,它只是为“最佳实践”保留的

显然,如果有人问你在面试中使用哪种语言,你会说IList,微笑,两人都会为自己的聪明而感到高兴。或者对于面向公众的API,IList。希望您能理解我的观点。

该界面确保您至少能获得所需的方法;了解接口的定义,即所有将由继承接口的任何类实现的抽象方法。因此,如果有人创建了一个自己的大型类,除了从接口继承的用于某些附加功能的方法之外,还有其他几种方法,而这些方法对您没有任何用处,那么最好使用对子类(在本例中为接口)的引用,并将具体的类对象分配给它

另外一个优点是,您的代码不受对具体类的任何更改的影响,因为您只订阅了具体类的几个方法,并且只要具体类继承了
public void Foo(IList<Bar> list)
{
     // Do Something with the list here.
}
IList<T> defines those methods (not including extension methods)
public Foo(List<int> a)
{
    a.Add(someNumber);
}
 int[] array = new[] {1, 2, 3};
 IList<int> ilist = array;

 ilist.Add(4); // throws System.NotSupportedException
 ilist.Insert(0, 0); // throws System.NotSupportedException
 ilist.Remove(3); // throws System.NotSupportedException
 ilist.RemoveAt(0); // throws System.NotSupportedException
if (!ilist.IsReadOnly)
{
   ilist.Add(4);
   ilist.Insert(0, 0); 
   ilist.Remove(3);
   ilist.RemoveAt(0);
}
else
{
   // what were you planning to do if you were given a read only list anyway?
}