JavaRush /Курси /C# SELF /Контракт на доступ за індексом:

Контракт на доступ за індексом: IList<T>

C# SELF
Рівень 28 , Лекція 3
Відкрита

1. Вступ

Отже, уявіть: у вас є колекція… і потрібно швидко отримати третій, сьомий або, скажімо, нульовий елемент. Або поміняти їх місцями. У масиві це легко — за індексом (array[3]). А що з колекціями? Адже не всі колекції підтримують індексацію однаково!

Тут на сцену виходить інтерфейс IList<T> — універсальний контракт, який вимагає від колекції підтримувати роботу з елементами за індексом. Якщо коротко: якщо ваша колекція реалізує IList<T>, можна сміливо звертатися до її елементів за індексом (як у масиві) і змінювати їх безпосередньо.

Аналогія:
Згадайте бібліотечну картку: у кожної книжки є свій порядковий номер на полиці, і ви завжди можете підійти до «третьої за рахунком» книжки й узяти її. Саме так поводиться колекція, яка підтримує IList<T>.

2. Загальна структура і методи IList<T>

Інтерфейс IList<T> — основа для багатьох колекцій. Він розширює ICollection<T> (а той, своєю чергою, IEnumerable<T>, що дає змогу ітерувати колекцію в циклі) і додає найголовніше: роботу з індексом.

Схема наслідування інтерфейсів:


IEnumerable<T>
      ▲
      │
ICollection<T>
      ▲
      │
  IList<T>
Наслідування інтерфейсів колекцій у .NET

Основні члени інтерфейсу IList<T>

Член Призначення
T this[int index] { get; set; }
Отримати або встановити елемент за індексом
int IndexOf(T item)
Знайти індекс першого входження елемента
void Insert(int index, T item)
Вставити елемент у задану позицію
void RemoveAt(int index)
Видалити елемент за індексом

Усі інші члени, такі як Add, Remove, Clear, Contains, походять з інтерфейсу ICollection<T>.

Ключова особливість: індексатор

Головна особливість IList<T> — індексатор. Завдяки йому можна писати:


var myList = new List<int> { 10, 20, 30 };
int secondValue = myList[1]; // Отримуємо 20
myList[2] = 42;              // Змінюємо третій елемент

3. Які колекції реалізують IList<T>

У стандартній бібліотеці .NET чимало відомих структур підтримують інтерфейс IList<T>. Розгляньмо найпопулярніші:

Колекція Індексація Опис
List<T>
Так Динамічний масив
T[]
Так Звичайні масиви підтримують індексацію
BindingList<T>
Так Використовується для прив’язування даних (data binding)
ObservableCollection<T>
Так Колекція зі сповіщеннями про зміни
Collection<T>
Так Базовий клас для колекцій

Увага:

LinkedList<T>
і
HashSet<T>
НЕ реалізують IList<T>, оскільки в них немає швидкої індексації (так, у LinkedList<T> немає list[5]!).

4. Приклади використання IList<T>

Отримання та встановлення за індексом


using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        IList<string> fruits = new List<string> { "Яблуко", "Банан", "Груша" };

        // Отримання другого елемента
        string fruit = fruits[1];
        Console.WriteLine(fruit); // Банан

        // Заміна третього елемента
        fruits[2] = "Апельсин";
        Console.WriteLine(fruits[2]); // Апельсин
    }
}

Вставлення та видалення за індексом


fruits.Insert(1, "Ківі");    // Вставляємо "Ківі" на друге місце
// Список тепер: "Яблуко", "Ківі", "Банан", "Апельсин"

fruits.RemoveAt(0);          // Видаляємо перший елемент ("Яблуко")
// Список тепер: "Ківі", "Банан", "Апельсин"

Пошук індексу елемента


int index = fruits.IndexOf("Апельсин"); // Поверне індекс (2) або -1, якщо не знайдено
if (index != -1)
    Console.WriteLine("Апельсин знаходиться на позиції: " + index);
else
    Console.WriteLine("Апельсин не знайдено");

5. Особливості реалізації та типові помилки

Працюючи з IList<T>, легко припуститися типових помилок, особливо якщо забути, що індексація починається з нуля, а довжина колекції — це поточна кількість елементів.

Наприклад, спроба звернутися до неіснуючого елемента:


Console.WriteLine(fruits[100]); // IndexOutOfRangeException!

Індекси в C# починаються з нуля. Якщо у списку 4 елементи, останній доступний індекс — 3.

Також варто памʼятати, що не всі реалізації IList<T> однаково швидкі. Наприклад, у масиві чи в List<T> доступ за індексом миттєвий (O(1)), а якщо ви створите власну колекцію на базі зв’язаного списку й додасте до неї IList<T>, операція може бути повільною. Стандартна бібліотека так не робить.

І ще один момент: якщо ви працюєте з масивом як із IList<T>, то можете змінювати елементи, але не можете змінювати розмір масиву. Методи Add, Remove, Insert тощо для масиву згенерують NotSupportedException.


int[] myArray = { 1, 2, 3 };
IList<int> listView = myArray; // Upcast

listView[0] = 42; // Працює!
listView.Add(99); // Згенерує NotSupportedException

6. Практичне застосування і навіщо це потрібно

У реальних проєктах дуже часто використовують колекції, що реалізують IList<T>, адже зручно мати змогу швидко звертатися до елементів за номером, змінювати їх, вставляти та видаляти за позицією. Наприклад:

  • Властивості у ViewModel для WPF чи WinForms, до яких прив’язуються списки елементів інтерфейсу.
  • Реалізація алгоритмів сортування, пошуку, перестановок, де потрібен доступ за індексом.
  • Модулі імпорту/експорту даних, що працюють із динамічним списком об’єктів.

На співбесіді запитання про відмінності IEnumerable<T>, ICollection<T> і IList<T> — класика. Розуміючи, за що відповідає кожен рівень, ви зможете впевнено пояснити інтервʼюеру, чому HashSet<T> не реалізує IList<T> (оскільки для нього важливіша унікальність елементів, а не порядок чи індекси).

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ