CodeGym /Kursy /C# SELF /Kontrakt na dostęp przez indeks:

Kontrakt na dostęp przez indeks: IList<T>

C# SELF
Poziom 28, Lekcja 3
Dostępny

1. Wprowadzenie

No więc wyobraź sobie: masz kolekcję... a musisz szybko dostać się do trzeciego, siódmego albo, powiedzmy, zerowego elementu. Albo zamienić je miejscami. W tablicy to proste — przez indeks (array[3]). A co z kolekcjami? Przecież nie każda kolekcja jest tak samo indeksowalna!

Tutaj na scenę wchodzi interfejs IList<T> — uniwersalny kontrakt, który wymaga od kolekcji obsługi pracy z elementami przez indeks. W skrócie: masz kolekcję, która implementuje IList<T> — możesz śmiało odwoływać się do jej elementów przez indeks (jak w tablicy) i zmieniać je na bieżąco.

Analogicznie:
Pomyśl o karcie bibliotecznej: każda książka ma swój numer na półce i zawsze możesz podejść do "trzeciej z kolei" książki i ją wziąć. Tak właśnie zachowuje się kolekcja wspierająca IList<T>.

2. Ogólna struktura i metody IList<T>

Interfejs IList<T> — bohater wielu kolekcji. Rozszerza ICollection<T> (a ten z kolei IEnumerable<T>, co pozwala przechodzić po kolekcji za pomocą pętli), i dodaje najważniejsze: pracę z indeksem.

Schemat dziedziczenia interfejsów:


IEnumerable<T>
      ▲
      │
ICollection<T>
      ▲
      │
  IList<T>
Dziedziczenie interfejsów kolekcji w .NET

Główne człony interfejsu IList<T>

Człon Przeznaczenie
T this[int index] { get; set; }
Pobierz lub ustaw element przez indeks
int IndexOf(T item)
Znajdź indeks pierwszego wystąpienia elementu
void Insert(int index, T item)
Wstaw element na podaną pozycję
void RemoveAt(int index)
Usuń element przez indeks

Wszystkie pozostałe człony, takie jak Add, Remove, Clear, Contains, pochodzą z interfejsu ICollection<T>.

Kluczowa rzecz: indeksator

Najważniejsza "cecha" IList<T> — obecność indeksatora. To taki syntaktyczny cukier, dzięki któremu możesz pisać:


var myList = new List<int> { 10, 20, 30 };
int secondValue = myList[1]; // Pobieramy 20
myList[2] = 42;              // Zmieniamy trzeci element

3. Jakie kolekcje implementują IList<T>

W standardowej bibliotece .NET wiele znanych struktur wspiera interfejs IList<T>. Zobaczmy na najpopularniejsze:

Kolekcja Indeksowanie Opis
List<T>
Tak Dynamiczna tablica
T[]
Tak Zwykłe tablice są indeksowane
BindingList<T>
Tak Używana do data binding
ObservableCollection<T>
Tak Lista z powiadomieniami
Collection<T>
Tak Bazowa klasa dla kolekcji

Uwaga:

LinkedList<T>
i
HashSet<T>
NIE implementują IList<T>, bo nie mają szybkiego indeksowania (tak, LinkedList<T> nie ma list[5]!).

4. Przykłady użycia IList<T>

Pobieranie i ustawianie przez indeks


using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        IList<string> fruits = new List<string> { "Jabłko", "Banan", "Gruszka" };

        // Pobieranie drugiego elementu
        string fruit = fruits[1];
        Console.WriteLine(fruit); // Banan

        // Zamiana trzeciego elementu
        fruits[2] = "Pomarańcza";
        Console.WriteLine(fruits[2]); // Pomarańcza
    }
}

Wstawianie i usuwanie przez indeks


fruits.Insert(1, "Kiwi");    // Wstawiamy "Kiwi" na drugie miejsce
// Lista teraz: "Jabłko", "Kiwi", "Banan", "Pomarańcza"

fruits.RemoveAt(0);          // Usuwamy pierwszy element ("Jabłko")
// Lista teraz: "Kiwi", "Banan", "Pomarańcza"

Wyszukiwanie indeksu elementu


int index = fruits.IndexOf("Pomarańcza"); // Zwróci indeks (2) lub -1, jeśli nie znaleziono
if (index != -1)
    Console.WriteLine("Pomarańcza znajduje się na pozycji: " + index);
else
    Console.WriteLine("Pomarańcza nie znaleziona");

5. Cechy implementacji i typowe błędy

Pracując z IList<T>, łatwo wpaść w kilka "pułapek", szczególnie jeśli zapomnisz, że indeksowanie zaczyna się od zera, a długość kolekcji — to aktualna liczba elementów.

Na przykład, próba odwołania się do nieistniejącego elementu:


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

Indeksy w C# — to jak kury nioski: zaczynają od zera, nie od jedynki. Jeśli w liście są 4 elementy, ostatni dostępny indeks to 3.

Warto też pamiętać, że nie wszystkie implementacje IList<T> są tak samo szybkie. Na przykład, w tablicy albo w List<T> dostęp przez indeks jest natychmiastowy (O(1)), ale jeśli zrobiłbyś własną kolekcję na bazie listy powiązanej i nałożył na nią IList<T>, operacja mogłaby być wolna. Chociaż standardowa biblioteka tak nie robi.

I jeszcze jedno: jeśli pracujesz z tablicą jako z IList<T>, możesz zmieniać elementy, ale nie możesz zmieniać rozmiaru tablicy. Metody Add, Remove, Insert itd. dla tablicy rzucą NotSupportedException.


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

listView[0] = 42; // Działa!
listView.Add(99); // Rzuci NotSupportedException

6. Praktyczne zastosowanie i po co to komu

W prawdziwych projektach prawie co druga kolekcja to coś, co implementuje IList<T>, bo wygodnie mieć możliwość szybkiego dostępu do elementów przez numer, zmieniać je, wstawiać i usuwać przez pozycję. Na przykład:

  • Właściwości interfejsowe we ViewModel WPF albo WinForms, gdzie bindują się listy elementów UI.
  • Implementacja algorytmów sortowania, wyszukiwania, permutacji, gdzie potrzebny jest dostęp przez indeks.
  • Moduły importu/eksportu danych, które pracują z dynamiczną listą obiektów.

Na rozmowie kwalifikacyjnej pytanie o różnice IEnumerable<T>, ICollection<T> i IList<T> — klasyka. Wiedząc, za co odpowiada każdy poziom, możesz pewnie wyjaśnić rekruterowi, czemu HashSet<T> nie implementuje IList<T> (bo unikalność jest ważniejsza niż kolejność i indeksy!).

2
Zadanie
C# SELF, poziom 28, lekcja 3
Niedostępne
Praca z metodami Insert i IndexOf
Praca z metodami Insert i IndexOf
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION