Основные отличия
Характеристика | 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. Важные нюансы
-
Преобразования:
IEnumerable<int> en = new List<int>();
IList<int> list = en.ToList();
-
Оптимизации:
- Некоторые методы проверяют реализацию IList для оптимизации
-
Неявная реализация:
- Array реализует IList, но методы типа Add() бросают исключение
Резюмируем:
IEnumerable предоставляет минимальный контракт для последовательного перечисления элементов, тогда как IList расширяет его возможностями индексации и модификации коллекции. Выбор между ними зависит от требуемого уровня доступа к данным - нужен ли только перебор элементов или полноценная работа с коллекцией.