When to use IList and when to use List
我知道i list是接口,list是具体的类型,但我仍然不知道何时使用每种类型。我现在要做的是,如果我不需要使用接口的sort或findall方法。我说的对吗?是否有更好的方法来决定何时使用接口或具体类型?
我遵循两条规则:
- 接受最基本的类型
- 返回用户需要的最丰富类型
因此,在编写接受集合的函数或方法时,编写它不是为了获取列表,而是为了获取IList、ICollection或IEnumerable。即使对于异类列表,通用接口仍然可以工作,因为System.Object也可以是T。如果您决定使用堆栈或其他数据结构,那么这样做可以避免您的头痛。如果您在函数中需要做的只是通过它来实现foreach,那么IEnumerable
另一方面,当从函数中返回一个对象时,您希望为用户提供尽可能丰富的操作集,而不必进行强制转换。因此,在这种情况下,如果它是一个内部列表,返回一个作为列表的副本。
由fxcop检查的Microsoft指南不鼓励在公共API中使用list
顺便说一下,我现在几乎总是将一维数组声明为ilist
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public interface IMyApi { IList<int> GetReadOnlyValues(); } public class MyApiImplementation : IMyApi { public IList<int> GetReadOnlyValues() { List<int> myList = new List<int>(); ... populate list return myList.AsReadOnly(); } } public class MyMockApiImplementationForUnitTests : IMyApi { public IList<int> GetReadOnlyValues() { IList<int> testValues = new int[] { 1, 2, 3 }; return testValues; } } |
人们总是忽略一件重要的事情:
可以将一个普通数组传递给接受
例如,考虑以下代码:
1 2 3 4 | private void test(IList<int> list) { list.Add(1); } |
如果按如下方式调用,则会得到运行时异常:
1 2 |
这是因为使用带有
因此,如果您打电话给
我同意李的建议,接受参数,但不返回。
如果您指定方法来返回一个接口,这意味着您可以在以后自由地更改确切的实现,而不必知道消耗方法。我认为我不需要从列表中进行更改,但后来必须进行更改才能使用自定义列表库来提供额外的功能。因为我只返回了一个ilist,所以使用库的人都不需要更改代码。
当然,这只需要应用于外部可见的方法(即公共方法)。我个人甚至在内部代码中也会使用接口,但由于您能够自己更改所有代码,所以如果您进行破坏性的更改,这并不是严格必要的。
可枚举的您应该尝试使用最不具体的类型来满足您的目的。IEnumerable不如IList具体当要循环访问集合中的项时,可以使用IEnumerable。
伊利斯特IList实现IEnumerable当需要按索引访问集合、添加和删除元素等时,应使用ilist。
表列表实现IList
最好使用尽可能低的基类型。这就给了界面的实现者,或者方法的使用者,在幕后使用他们喜欢的任何东西的机会。
对于集合,应尽可能使用IEnumerable。这提供了最大的灵活性,但并不总是适合的。
如果您在一个方法内工作(或者在某些情况下甚至在一个类或程序集内工作),而外部没有人会看到您在做什么,那么使用列表的完整性。但是,如果您正在与外部代码交互,比如当您从方法返回列表时,那么您只希望声明接口,而不必将自己绑定到特定的实现,特别是如果您无法控制之后谁编译代码。如果您从一个具体的类型开始,并决定改为另一个类型,即使它使用相同的接口,除非您从一个接口或抽象基类型开始,否则您将破坏其他人的代码。
使用最通用的可用类型(在本例中是IList,甚至更好的是IEnumerable接口)通常会更好,以便以后方便地切换实现。
然而,在.NET 2.0中,有一件烦人的事情-ilist没有sort()方法。您可以使用提供的适配器:
1 | ArrayList.Adapter(list).Sort() |
我不认为这类事情有硬性和快速性的规则,但我通常以尽可能轻的方式进行指导,直到绝对必要为止。
例如,假设您有一个
1 2 3 4 5 6 7 | public class Group { private IList<Person> people; public Group() { this.people = new List<Person>(); } } |
而且,如果您甚至不需要
a list对象允许您创建一个列表,向其添加内容,删除它,更新它,索引到它等等。只要您想要一个通用列表,在其中指定对象类型,就可以使用列表。
另一方面,IList是一个接口。基本上,如果您想创建自己的列表类型,比如一个名为booklist的列表类,那么您可以使用该接口为新类提供基本的方法和结构。当您想创建自己的实现列表的特殊子类时,可以使用IList。
另一个区别是:IList是接口,无法实例化。列表是一个类,可以实例化。它的意思是:
您应该仅在需要时使用该接口,例如,如果您的列表被强制转换为列表以外的IList实现。例如,当您使用nhibernate时,这是正确的,它在检索数据时将ilist强制转换为nhibernate包对象。
如果列表是您将用于某个集合的唯一实现,那么可以将其声明为具体的列表实现。
在我经常遇到的情况下,我很少直接使用ilist。
通常我只是用它作为方法的参数
1 2 3 4 | void ProcessArrayData(IList almostAnyTypeOfArray) { // Do some stuff with the IList array } |
这将允许我对.NET框架中的几乎任何数组执行一般处理,除非它使用IEnumerable而不是IList,这有时会发生。
它实际上取决于您需要的功能类型。我建议在大多数情况下使用List类。当您需要创建一个自定义数组时,IList是最好的选择,它可能具有一些非常具体的规则,您希望将这些规则封装在集合中,这样您就不会重复自己的操作,但仍然希望.NET将其识别为列表。