Czym są indeksy w C#? Jakie rodzaje indeksów istnieją i czy używałeś ich w praktyce?
sobes.tech AI
Odpowiedź od AI
Indeksatory w C# pozwalają na dostęp do instancji klasy lub struktury jak do tablicy, używając składni []. Nie są statyczne i przeciążają operator [].
Indeksatory
Indeksatory pozwalają na zdefiniowanie logiki dostępu do elementów kolekcji lub struktury danych w obrębie klasy.
public class MyCollection
{
private string[] data = new string[10];
// Indeksator umożliwiający pobieranie lub ustawianie elementu po indeksie
public string this[int index]
{
get
{
// Sprawdzenie granic
if (index >= 0 && index < data.Length)
{
return data[index];
}
else
{
throw new IndexOutOfRangeException();
}
}
set
{
// Sprawdzenie granic
if (index >= 0 && index < data.Length)
{
data[index] = value;
}
else
{
throw new IndexOutOfRangeException();
}
}
}
}
Typy parametrów indeksatorów
Indeksatory mogą przyjmować dowolną liczbę parametrów dowolnego typu, nie ograniczając się tylko do typów całkowitych.
public class DictionaryLike
{
private Dictionary<string, string> _dictionary = new Dictionary<string, string>();
// Indeksator z parametrem typu string
public string this[string key]
{
get
{
if (_dictionary.ContainsKey(key))
{
return _dictionary[key];
}
else
{
return null; // lub rzucić wyjątek
}
}
set
{
_dictionary[key] = value;
}
}
}
Przeciążanie indeksatorów
Można tworzyć przeciążone indeksatory z różnymi sygnaturami (zestawem i typami parametrów).
public class Matrix
{
private int[,] data;
public Matrix(int rows, int cols)
{
data = new int[rows, cols];
}
// Indeksator z dwoma parametrami typu int
public int this[int row, int col]
{
get
{
// Sprawdzenie granic
if (row >= 0 && row < data.GetLength(0) && col >= 0 && col < data.GetLength(1))
{
return data[row, col];
}
else
{
throw new IndexOutOfRangeException();
}
}
set
{
// Sprawdzenie granic
if (row >= 0 && row < data.GetLength(0) && col >= 0 && col < data.GetLength(1))
{
data[row, col] = value;
}
else
{
throw new IndexOutOfRangeException();
}
}
}
}
Zakresowe indeksy (Ranges & Indices)
W C# 8.0 wprowadzone zostały nowe typy System.Index i System.Range, które pozwalają na użycie składni do odwoływania się do elementów od końca kolekcji (^) oraz do uzyskiwania podzakresów (..). Te pojęcia często nazywa się "indeksami", ale różnią się od klasycznych indeksatorów.
using System;
public class ArrayExample
{
public static void Main(string[] args)
{
string[] words = { "the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog" };
// Użycie System.Index do dostępu od końca
Index last = ^1; // Indeks ostatniego elementu
Console.WriteLine(words[last]); // dog
// Użycie System.Range do uzyskania podzakresu
Range middle = 1..4; // Elementy od indeksu 1 do (ale nie włącznie) indeksu 4
string[] subset = words[middle]; // {"quick", "brown", "fox"}
// Range z użyciem System.Index
Range fromEnd = ^3..; // od trzeciego od końca do końca
string[] suffix = words[fromEnd]; // {"the", "lazy", "dog"}
}
}
Praktyczne zastosowanie
Aktywnie korzystałem z indeksatorów podczas tworzenia własnych klas kolekcji lub opakowań nad istniejącymi, aby zapewnić bardziej intuicyjny dostęp do danych. Na przykład:
- Tworzenie klas reprezentujących macierze lub dane wielowymiarowe, gdzie dostęp po współrzędnych
matrix[row, col]miał sens. - Tworzenie opakowań nad
Dictionary<>lub innymi kolekcjami, gdzie dostęp po kluczu przez indeksator poprawiał czytelność kodu. - W prostych kolekcjach, gdzie potrzebna była składniowa wygoda dostępu, podobna do tablicy.
Indeksy zakresowe (System.Index i System.Range) używałem do bardziej zwięzłego dostępu do części tablic lub list, co jest szczególnie przydatne przy pracy z podłańcuchami lub częściami danych z kolekcji.