何时使用IList以及何时使用List

时间:2008-08-19 23:09:55

标签: c# .net

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

12 个答案:

答案 0 :(得分:162)

我遵循两条规则:

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

因此,在编写采用集合的函数或方法时,不要将其写入List,而是写入IList< T>,ICollection< T>或IEnumerable< T>。即使对于异构列表,通用接口仍然可以工作,因为System.Object也可以是T。如果您决定使用堆栈或其他一些数据结构,这样做可以帮助您避免头痛。如果你需要在函数中做的只是通过它,IEnumerable< T>真的是你应该要求的全部。

另一方面,当从函数返回一个对象时,你想给用户一个最丰富的操作集,而不必抛弃它们。那么在那种情况下,如果它是List< T>在内部,将副本作为List< T>返回。

答案 1 :(得分:54)

由FxCop检查的Microsoft指南不鼓励使用List< T>。在公共API中 - 更喜欢IList< T>。

顺便说一句,我现在几乎总是将一维数组声明为IList< T>,这意味着我可以始终使用IList< T> .Count属性而不是Array.Length。例如:

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;
    }
}

答案 2 :(得分:25)

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

您可以将普通数组传递给接受IList<T>参数的内容,然后您可以调用IList.Add()并收到运行时异常:

Unhandled Exception: System.NotSupportedException: Collection was of a fixed size.

例如,请考虑以下代码:

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

如果按以下方式调用,则会出现运行时异常:

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

这是因为使用IList<T>的普通数组违反了Liskov替换原则。

因此,如果您致电IList<T>.Add(),可能需要考虑要求List<T>代替IList<T>

答案 3 :(得分:24)

我同意Lee关于获取参数的建议,但不会返回。

如果指定返回接口的方法,则意味着您可以在以后更改确切的实现,而无需消费方法。我以为我永远不需要改变列表&lt; T&gt;但不得不稍后更改为使用自定义列表库来提供它提供的额外功能。因为我只返回了一个IList&lt; T&gt;使用该库的人都不得不改变他们的代码。

当然,只需要应用于外部可见的方法(即公共方法)。我个人甚至在内部代码中使用接口,但是如果你进行重大更改,你可以自己更改所有代码,这不是绝对必要的。

答案 4 :(得分:17)

<强>的IEnumerable 你应该尝试使用适合你目的的最不具体的类型。 IEnumerable不如IList特异 如果要循环遍历集合中的项目,可以使用IEnumerable

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

<强>列表 List实现IList

答案 5 :(得分:9)

最好尽可能使用最低的基本类型。这使得您的界面的实现者或您的方法的消费者有机会在幕后使用他们喜欢的任何内容。

对于集合,您应该尽可能使用IEnumerable。这提供了最大的灵活性,但并不总是适合。

答案 6 :(得分:5)

如果您在单个方法中工作(或者在某些情况下甚至在单个类或程序集中工作)并且外面没有人会看到您正在做什么,请使用List的完整性。但是,如果您正在与外部代码交互,例如当您从方法返回列表时,那么您只需要声明接口而不必将自己绑定到特定实现,特别是如果您无法控制谁编译您的之后的代码。如果你开始使用具体的类型并且你决定改为另一个,即使它使用相同的接口,你也会破坏别人的代码,除非你开始使用接口或抽象基类型。

答案 7 :(得分:4)

我不认为这类事情有严格的规则,但我通常会遵循使用最轻微的方法,直到绝对必要。

例如,假设您有一个Person类和一个Group类。 Group实例有很多人,所以这里的列表是有意义的。当我在Group中声明列表对象时,我将使用IList<Person>并将其实例化为List

public class Group {
  private IList<Person> people;

  public Group() {
    this.people = new List<Person>();
  }
}

而且,如果您甚至不需要IList中的所有内容,那么您也可以始终使用IEnumerable。使用现代编译器和处理器,我认为没有任何速度差异,所以这只是风格问题。

答案 8 :(得分:4)

你最常使用最常用的类型,在这种情况下是IList甚至更好的IEnumerable接口,这样你就可以在以后方便地切换实现。

然而,在.NET 2.0中,有一件令人烦恼的事情--Illist没有 Sort()方法。您可以使用提供的适配器:

ArrayList.Adapter(list).Sort()

答案 9 :(得分:2)

AList对象允许您创建一个列表,向其添加内容,删除它,更新它,索引它等等。只要您想要一个通用List,您可以在其中指定对象类型就可以使用List,就是这样。

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

另一个不同之处是:  IList是一个接口,无法实例化。 List是一个类,可以实例化。这意味着:

IList<string> MyList = new IList<string>();

List<string> MyList = new List<string>

答案 10 :(得分:1)

在我经常遇到的情况下,我很少直接使用IList。

通常我只是将它用作方法的参数

void ProcessArrayData(IList almostAnyTypeOfArray)
{
    // Do some stuff with the IList array
}

这将允许我对.NET框架中的几乎任何数组进行泛型处理,除非它使用IEnumerable而不是IList,这有时会发生。

它真正归结为您需要的功能。在大多数情况下,我建议使用List类。当您需要创建一个可能具有某些特定规则的自定义数组时,IList是最佳选择,这些规则要封装在集合中,这样您就不会重复自己,但仍希望.NET将其识别为列表。< / p>

答案 11 :(得分:1)

只有在需要时才应使用该接口,例如,如果您的列表已转换为除List之外的IList实现。例如,当您使用NHibernate时,这是正确的,它在检索数据时将ILists转换为NHibernate包对象。

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