C# 何时使用IList和何时使用列表

C# 何时使用IList和何时使用列表,c#,.net,C#,.net,我知道IList是接口,List是具体类型,但我仍然不知道何时使用每个类型。我现在要做的是,如果我不需要使用接口的Sort或FindAll方法。我说得对吗?是否有更好的方法来决定何时使用界面或具体类型?我认为这类事情没有硬性规定,但我通常遵循的原则是在绝对必要之前使用最轻的方式 例如,假设您有一个个人类和一个组类。一个组实例有很多人,所以这里的列表是有意义的。当我在组中声明列表对象时,我将使用IList并将其实例化为列表 public class Group { private IList&

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

我认为这类事情没有硬性规定,但我通常遵循的原则是在绝对必要之前使用最轻的方式

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

public class Group {
  private IList<Person> people;

  public Group() {
    this.people = new List<Person>();
  }
}
公共类组{
私人主义者;
公共组(){
this.people=新列表();
}
}

而且,如果您甚至不需要IList中的所有内容,也可以使用
IEnumerable
。对于现代的编译器和处理器,我认为速度并没有什么差别,所以这更多的是风格问题。

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

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

void ProcessArrayData(IList almostAnyTypeOfArray)
{
    // Do some stuff with the IList array
}
这将允许我在.NET framework中的几乎任何数组上执行通用处理,除非它使用IEnumerable而不是IList,这有时会发生


这实际上取决于你需要什么样的功能。我建议在大多数情况下使用List类。IList最适用于需要创建自定义数组的情况,该数组可能包含一些非常特定的规则,您希望将这些规则封装到集合中,这样您就不会重复自己的操作,但仍希望.NET将其识别为列表。

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

您应该仅在需要时使用该接口,例如,如果您的列表被强制转换为list实现,而不是list实现。例如,当您使用NHibernate时,这是正确的,它在检索数据时将ILists强制转换为NHibernate包对象


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

始终最好使用尽可能低的基类型。这使接口的实现者或方法的使用者有机会在幕后使用他们喜欢的任何东西


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

我遵循两条规则:

  • 接受最基本的工作类型
  • 返回用户需要的最丰富类型
因此,在编写接受集合的函数或方法时,编写它不是为了接受列表,而是为了接受IList、ICollection或IEnumerable。由于System.Object也可以是T,所以即使对于异构列表,通用接口仍然可以工作。如果您决定在将来使用堆栈或其他数据结构,那么这样做可以省去您的头疼。如果您需要在函数中执行的只是foreach,那么IEnumerable就是您真正需要的


另一方面,当从函数中返回一个对象时,您希望为用户提供最丰富的操作集,而无需用户进行转换。因此,在这种情况下,如果它是一个内部列表,则返回一个副本作为列表。

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

如果您指定了返回接口的方法,这意味着您以后可以自由地更改确切的实现,而不必让使用方法知道。我想我永远不需要改变列表,但后来不得不改变,使用自定义列表库来实现它提供的额外功能。因为我只返回了一个IList,所以使用该库的人都不必更改他们的代码


当然,这只需要应用于外部可见的方法(即公共方法)。我个人甚至在内部代码中也使用接口,但是如果您进行了破坏性的更改,您可以自己更改所有代码,因此严格来说这不是必需的。

FxCop检查的Microsoft指南不鼓励在公共API中使用列表-首选IList

顺便说一句,我现在几乎总是将一维数组声明为IList,这意味着我可以始终使用IList.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;
    }
}
公共接口IMyApi
{
IList GetReadOnlyValue();
}
公共类myapi实现:IMyApi
{
公共IList GetReadOnlyValue()
{
List myList=新列表();
…填充列表
返回myList.AsReadOnly();
}
}
用于单元测试的公共类MyMockApi实现:IMyApi
{
公共IList GetReadOnlyValue()
{
IList testValues=newint[]{1,2,3};
返回测试值;
}
}

使用最通用的可用类型(在本例中为IList)或IEnumerable接口通常会更好,这样您可以在以后方便地切换实现

然而,在.NET2.0中,有一件恼人的事情-IList没有Sort()方法。您可以改用提供的适配器:

ArrayList.Adapter(list).Sort()

IEnumerable
你应该试着使用它
IList<string> MyList = new IList<string>();

List<string> MyList = new List<string>
private void test(IList<int> list)
{
    list.Add(1);
}
int[] array = new int[0];
test(array);