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


当前回答

由FxCop检查的微软指南不鼓励在公共api中使用List<T> -更倾向于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;
    }
}

其他回答

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

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

由FxCop检查的微软指南不鼓励在公共api中使用List<T> -更倾向于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;
    }
}

我不认为这类事情有严格的规则,但我通常会遵循使用尽可能轻松的方式的指导方针,直到绝对必要的时候。

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

public class Group {
  private IList<Person> people;

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

而且,如果你甚至不需要IList中的所有东西,你也可以使用IEnumerable。对于现代的编译器和处理器,我不认为它们真的有任何速度上的差异,所以这只是风格的问题。

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

然而,在。net 2.0中,有一个恼人的事情——IList没有Sort()方法。您可以使用提供的适配器:

ArrayList.Adapter(list).Sort()

我有两条原则:

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

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

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