我知道IList是接口,List是具体类型,但我仍然不知道何时使用每一个。我现在做的是,如果我不需要Sort或FindAll方法,我使用接口。我说的对吗?是否有更好的方法来决定何时使用接口或具体类型?


当前回答

一个List对象允许你创建一个列表,添加东西到它,删除它,更新它,索引到它等等。当你只想要一个泛型列表时,List就会被使用,你可以在其中指定对象类型。

另一方面,IList是一个接口。基本上,如果您想创建自己的自定义列表,比如一个名为BookList的列表类,那么您可以使用接口为您的新类提供基本方法和结构。IList用于当你想创建自己的特殊子类来实现List时。

另一个区别是: IList是一个接口,不能被实例化。List是一个类,可以实例化。它的意思是:

IList<string> list1 = new IList<string>(); // this is wrong, and won't compile

IList<string> list2 = new List<string>();  // this will compile
List<string> list3 = new List<string>();   // this will compile

其他回答

你应该只在你需要它的时候使用这个接口,例如,如果你的列表被强制转换为一个IList实现而不是list。这是真的,例如,当你使用NHibernate,它在检索数据时将列表转换为NHibernate包对象。

如果List是您将用于某个集合的唯一实现,则可以将其声明为具体的List实现。

If you're working within a single method (or even in a single class or assembly in some cases) and no one outside is going to see what you're doing, use the fullness of a List. But if you're interacting with outside code, like when you're returning a list from a method, then you only want to declare the interface without necessarily tying yourself to a specific implementation, especially if you have no control over who compiles against your code afterward. If you started with a concrete type and you decided to change to another one, even if it uses the same interface, you're going to break someone else's code unless you started off with an interface or abstract base type.

有一件重要的事情,人们似乎总是忽视:

你可以将一个普通数组传递给接受IList<T>参数的对象,然后你可以调用IList. add(),并将收到一个运行时异常:

未处理异常:系统。NotSupportedException:集合大小固定。

例如,考虑以下代码:

private void test(IList<int> list)
{
    list.Add(1);
}

如果你像下面这样调用它,你会得到一个运行时异常:

int[] array = new int[0];
test(array);

这是因为使用带有IList<T>的普通数组违反了利斯科夫替换原则。

因此,如果你调用IList<T>. add(),你可能需要考虑使用List<T>而不是IList<T>。

IEnumerable 您应该尝试使用最不特定的类型来满足您的目的。 IEnumerable没有IList那么具体。 当您希望循环遍历集合中的项时,可以使用IEnumerable。

IList IList实现了IEnumerable。 当你需要通过索引访问你的集合,添加和删除元素等时,你应该使用IList。

列表 List实现了IList。

我有两条原则:

接受最基本的工作类型 返回用户需要的最丰富的类型

因此,当编写一个接受集合的函数或方法时,不要让它接受List,而是让它接受IList<T>、ICollection<T>或IEnumerable<T>。泛型接口即使对于异构列表也仍然有效,因为System。Object也可以是T。如果您决定在以后使用Stack或其他数据结构,这样做将为您省去麻烦。如果在函数中所需要做的只是逐个遍历它,那么IEnumerable<T>才是真正需要的。

另一方面,当从函数返回一个对象时,您希望为用户提供尽可能丰富的操作集,而不需要他们进行强制转换。在这种情况下,如果内部是List<T>,返回一个List<T>的副本。