Когда использовать IList и когда использовать List

Я знаю, что IList - это интерфейс, а List - конкретный тип, но я до сих пор не знаю, когда использовать каждый из них. Что я делаю сейчас, если мне не нужны методы Sort или FindAll, я использую интерфейс. Я прав? Есть ли лучший способ решить, когда использовать интерфейс или конкретный тип?

177 .netc#
19.08.2008 23:09:54
Если кому-то все еще интересно, я найду лучшие ответы здесь: stackoverflow.com/questions/400135/listt-or-ilistt
Crismogram 22.05.2018 03:13:30
12 ОТВЕТОВ
РЕШЕНИЕ

Есть два правила, которым я следую:

  • Принять самый основной тип, который будет работать
  • Верните самый богатый тип, который понадобится вашему пользователю

Поэтому, когда вы пишете функцию или метод, который принимает коллекцию, пишите ее не для List, а для IList <T>, ICollection <T> или IEnumerable <T>. Универсальные интерфейсы по-прежнему будут работать даже для разнородных списков, поскольку System.Object также может быть буквой T. Это избавит вас от головной боли, если вы решите использовать стек или какую-то другую структуру данных в будущем. Если все, что вам нужно сделать в функции - это foreach, то IEnumerable <T> - это действительно все, о чем вы должны просить.

С другой стороны, когда вы возвращаете объект из функции, вы хотите предоставить пользователю максимально богатый набор операций без необходимости их наложения. Так что в этом случае, если это внутренний список List <T>, верните копию как List <T>.

171
20.08.2008 01:58:57
Вы не должны относиться к типам ввода / вывода по-другому. Входные и выходные типы должны как наиболее базовый тип (предпочтительно интерфейс) , который будет поддерживать потребности клиентов. Инкапсуляция основана на том, чтобы как можно меньше рассказывать клиентам о реализации вашего класса. Если вы вернете конкретный список, вы не сможете изменить его на какой-либо другой лучший тип, не заставив всех ваших клиентов перекомпилировать / обновить.
Ash 12.09.2010 08:53:59
Я не согласен с этими 2 правилами ... Я бы использовал наиболее примитивный тип и specialy при возврате в этом случае IList (лучше IEnumarable), и вы должны работать со List внутри своей функции. Затем, когда вам нужно «добавить» или «отсортировать», используйте коллекцию, если нужно больше, используйте список. Таким образом, мое жесткое правило будет таким: НАЧАТЬ всегда с IENumarable, а если вам нужно больше, продлить ...
ethem 26.04.2013 18:25:27
Для вашего удобства у «двух правил» есть название: принцип робастности (он же закон Постеля) .
easoncxz 13.06.2015 11:12:20
Независимо от того, на чьей стороне споры о том, возвращать ли самый базовый тип или самый богатый тип, следует учитывать, что при возврате очень упрощенного интерфейса часто потребляющий код может - хотя и не всегда - использовать if...elseцепочку с isключевым словом для вычисления гораздо более богатый тип для него и в конечном итоге приведение к нему и использование этого в любом случае. Таким образом, вы не обязательно гарантируете что-либо скрыть, используя простой интерфейс, вместо того, чтобы просто скрывать это. Однако усложнение может также заставить автора потребляющего кода дважды подумать о том, как он его использует.
Panzercrisis 7.09.2016 20:04:27
Я очень сильно не согласен по поводу пункта № 2, особенно если это граница сервиса / API. Возвращение изменяемых коллекций может создать впечатление, что коллекции являются «живыми» и вызывают такие методы, как Add()и Remove()могут иметь последствия, выходящие за рамки просто коллекции. Возврат интерфейса, доступного только для чтения, например, IEnumerableчасто используется для методов извлечения данных. Ваш потребитель может проецировать его в более богатый тип по мере необходимости.
STW 23.09.2016 22:29:07

Я не думаю, что существуют жесткие и быстрые правила для такого рода вещей, но я обычно придерживаюсь принципа использования как можно более легкого пути, пока это не станет абсолютно необходимым.

Например, допустим, у вас есть Personкласс и Groupкласс. В Groupэкземпляре много людей, поэтому список здесь имеет смысл. Когда я объявляю объект списка в, Groupя буду использовать IList<Person>и создавать его как List.

public class Group {
  private IList<Person> people;

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

И, если вам даже не нужно все в IListвас, вы всегда можете использовать IEnumerableтоже. С современными компиляторами и процессорами, я не думаю, что есть какая-то разница в скорости, так что это больше вопрос стиля.

4
19.08.2008 23:17:07
почему бы не сделать его просто списком в первую очередь? Я до сих пор не понимаю, почему вы получаете бонус от создания IList, тогда как в конструкторе вы превращаете его в List <>
chobo2 19.12.2011 20:56:50
Я согласен, если вы явно создаете объект List <T>, то вы теряете преимущество интерфейса?
The_Butcher 18.09.2017 13:15:48

В ситуациях, с которыми я обычно сталкиваюсь, я редко использую IList напрямую.

Обычно я просто использую это как аргумент метода

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

Это позволит мне выполнять общую обработку практически любого массива в среде .NET, если только он не использует IEnumerable, а не IList, что иногда случается.

Это действительно сводится к той функциональности, которая вам нужна. Я бы предложил использовать класс List в большинстве случаев. IList лучше всего подходит для случаев, когда вам нужно создать собственный массив, который может иметь некоторые очень специфические правила, которые вы хотите инкапсулировать в коллекцию, чтобы вы не повторялись, но все же хотели, чтобы .NET распознал его как список.

1
19.08.2008 23:17:46

Если вы работаете в одном методе (или даже в одном классе или сборке в некоторых случаях), и никто за пределами не увидит, что вы делаете, используйте полноту List. Но если вы взаимодействуете с внешним кодом, как, например, когда вы возвращаете список из метода, вам нужно только объявить интерфейс, не привязывая себя к конкретной реализации, особенно если вы не можете контролировать, кто компилирует против вашего код потом. Если вы начали с конкретного типа и решили заменить его на другой, даже если он использует тот же интерфейс, вы нарушите чужой код, если только вы не начали с интерфейса или абстрактного базового типа.

5
19.08.2008 23:20:12

Вы должны использовать интерфейс только в том случае, если он вам нужен, например, если ваш список приведен к реализации IList, отличной от List. Это верно, например, когда вы используете NHibernate, который преобразует ILists в объект-мешок NHibernate при получении данных.

Если List - единственная реализация, которую вы когда-либо будете использовать для определенной коллекции, не стесняйтесь объявлять ее как конкретную реализацию List.

2
19.08.2008 23:20:22

Всегда лучше использовать минимально возможный базовый тип. Это дает разработчику вашего интерфейса или потребителю вашего метода возможность использовать все что угодно за кулисами.

Для коллекций вы должны стремиться использовать IEnumerable, где это возможно. Это дает большую гибкость, но не всегда подходит.

9
19.08.2008 23:41:13
Всегда лучше принять минимально возможный базовый тип. Возвращение это другая история. Выберите, какие варианты могут быть полезны. Так вы думаете, что ваш клиент может захотеть использовать индексированный доступ? Не ToList()позволяйте им возвращать возвращенный IEnumerable<T>список, а IList<T>вместо этого возвращайте . Теперь клиенты могут извлечь выгоду из того, что вы можете предоставить без труда.
Timo 24.10.2016 12:06:52

Я бы согласился с советом Ли о том, чтобы брать параметры, но не возвращать.

Если вы указываете свои методы для возврата интерфейса, это означает, что вы можете изменить точную реализацию позже, не обращая внимания на метод потребления. Я думал, что мне никогда не понадобится переходить из List <T>, но позже пришлось изменить его, чтобы использовать настраиваемую библиотеку списков для дополнительной функциональности, которую она предоставляла. Поскольку я только возвратил IList <T>, ни один из людей, которые использовали библиотеку, не должен был менять свой код.

Конечно, это нужно применять только к методам, которые являются внешне видимыми (например, общедоступные методы). Я лично использую интерфейсы даже во внутреннем коде, но, поскольку вы можете изменить весь код самостоятельно, если вносите критические изменения, это не является строго необходимым.

24
20.08.2008 09:12:08

Руководства Microsoft, проверенные FxCop, не рекомендуют использовать 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;
    }
}
55
17.09.2008 17:08:27
Мне больше всего нравится это объяснение / пример!
JonH 4.11.2009 18:12:49

Чаще всего вам лучше использовать наиболее общий используемый тип, в данном случае IList или даже лучше интерфейс IEnumerable, чтобы можно было удобно переключать реализацию в более позднее время.

Однако в .NET 2.0 есть одна неприятная вещь - у IList нет метода Sort () . Вместо этого вы можете использовать прилагаемый адаптер:

ArrayList.Adapter(list).Sort()
4
17.09.2008 17:22:50

IEnumerable
Вам следует использовать наименее конкретный тип, который соответствует вашим целям.
IEnumerableменее конкретен, чем IList.
Вы используете, IEnumerableкогда хотите перебрать элементы в коллекции.

IList
IList реализует IEnumerable.
Вы должны использовать, IListкогда вам нужен доступ по индексу к вашей коллекции, добавлять и удалять элементы и т.д ...

Список
List инструментов IList.

19
21.03.2020 06:40:01
Отличный, четкий ответ, который я пометил как полезный. Однако я хотел бы добавить, что для большинства разработчиков большую часть времени не стоит беспокоиться о крошечной разнице в размере и производительности программы: в случае сомнений просто используйте List.
Graham Laight 10.09.2014 08:57:54

Объект AList позволяет создавать список, добавлять в него элементы, удалять его, обновлять, индексировать в него и т. Д. Список используется всякий раз, когда вам просто нужен общий список, в котором вы указываете тип объекта и все.

IList, с другой стороны, является интерфейсом. По сути, если вы хотите создать свой собственный тип List, скажем, класс списка с именем BookList, то вы можете использовать интерфейс, чтобы дать вам базовые методы и структуру для вашего нового класса. IList предназначен для случаев, когда вы хотите создать свой собственный специальный подкласс, который реализует List.

Другое отличие: IList является интерфейсом и не может быть создан. Список является классом и может быть создан. Это значит:

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

List<string> MyList = new List<string>
1
19.08.2013 05:13:44

Есть важная вещь, которую люди, кажется, всегда упускают:

Вы можете передать простой массив чему-то, что принимает 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>нарушает принцип подстановки Лискова.

По этой причине, если вы звоните, IList<T>.Add()вы можете рассмотреть вопрос о необходимости List<T>вместо IList<T>.

28
30.10.2013 13:47:05
Это тривиально верно для каждого интерфейса. Если вы хотите довести доводы до конца, вы можете поспорить, что никогда не будете использовать какой-либо интерфейс вообще, потому что некоторая реализация этого может привести к отказу. Если, с другой стороны, рассмотрим предложение , данное ОП предпочитать List<T>более IList<T>, вы также должны быть осведомлены о причинах , почему IList<T>рекомендуется. (Например, blogs.msdn.microsoft.com/kcwalina/2005/09/26/… )
Micha Wiedenmann 29.08.2017 07:49:48
@MichaWiedenmann Мой ответ здесь зависит от того, когда вы звоните IList<T>.Add(). Я не говорю, что вы не должны использовать IList<T>- я просто указываю на возможную ловушку. (Я склонен использовать IEnumerable<T>или IReadOnlyList<T>или IReadOnlyCollection<T>предпочитаю, IList<T>если смогу.)
Matthew Watson 29.08.2017 08:06:49