В чем разница между IList и IEnumerable ?csharp-95

Основные отличия

Характеристика IEnumerable<T> IList<T>
Назначение Только перечисление элементов Полноценная коллекция
Модификация Только чтение Чтение и запись
Доступ по индексу Не поддерживается Поддерживается
Производительность Ленивое выполнение Немедленный доступ
Использование LINQ, foreach Работа с коллекциями

1. Определение интерфейсов

IEnumerable:

public interface IEnumerable<T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}
  • Минимальный интерфейс для поддержки foreach
  • Позволяет только последовательное чтение элементов
  • Основа LINQ-запросов

IList:

public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
{
    T this[int index] { get; set; }
    int IndexOf(T item);
    void Insert(int index, T item);
    void RemoveAt(int index);
}
  • Наследует от ICollection и IEnumerable
  • Добавляет методы для модификации коллекции
  • Поддерживает доступ по индексу

2. Возможности

IEnumerable:

IEnumerable<int> numbers = Enumerable.Range(1, 10);
foreach (var n in numbers) { ... }
  • Только итерация
  • Ленивое выполнение (yield return)
  • Не знает о количестве элементов

IList:

IList<int> list = new List<int> {1, 2, 3};
list.Add(4);
list[0] = 5;
  • Полноценная работа с коллекцией
  • Прямой доступ к элементам
  • Знает о количестве элементов (Count)

3. Производительность

IEnumerable:

  • Может быть "ленивым" (например, LINQ-запрос)
  • Не хранит элементы в памяти (может генерировать на лету)
  • Меньшие требования к памяти

IList:

  • Обычно хранит элементы в памяти
  • Быстрый доступ по индексу (O(1))
  • Операции модификации могут быть дорогими

4. Типичные реализации

IEnumerable:

  • LINQ-запросы (Where, Select и т.д.)
  • yield-методы
  • Коллекции только для чтения

IList:

  • List, Array, ObservableCollection
  • Большинство изменяемых коллекций

5. Практическое использование

Когда использовать IEnumerable:

public IEnumerable<string> GetNames()
{
    yield return "Alice";
    yield return "Bob";
}
  • Возврат данных из метода
  • Работа с LINQ
  • Когда не нужно модифицировать коллекцию

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

public void ProcessItems(IList<int> items)
{
    items.Add(42);
    var x = items[0];
}
  • Когда нужен доступ по индексу
  • При необходимости модификации коллекции
  • Для работы с API, требующим индексации

6. Важные нюансы

  1. Преобразования:

    IEnumerable<int> en = new List<int>();
    IList<int> list = en.ToList();
    
  2. Оптимизации:

    • Некоторые методы проверяют реализацию IList для оптимизации
  3. Неявная реализация:

    • Array реализует IList, но методы типа Add() бросают исключение

Резюмируем:

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