Cześć,
W dzisiejszym poście poruszymy temat Indekserów.
Czym są i jak z nich korzystać?
Zapraszam do lektury.
Jedna z dobrych praktyk programowania obiektowego mówi, że na poziomie klasy zadeklarowane zmienne powinny być prywatne. Jeżeli wiemy że będziemy się odwoływać się do nich z kodu umieszczonego poza klasą, to powinniśmy zaimplementować publiczne właściwości, które będą na nich operować. A co w przypadku jeśli mamy tablicę zadeklarowaną na poziomie klasy?
W języku C# z pomocą przychodzą nam indeksatory (ang. indexers).
Zaimplementowanie indeksatora pozwala nam odwoływać się do tablicy w klasie po samej nazwie obiektu i indeksie. Istnieje tutaj jednak pewne ograniczenie, klasa zawierająca indeksator może mieć zadeklarowaną tylko jedną tablicę.
Podobnie jak właściwość, indeksator musi zawierać co najmniej jeden akcesor (GET lub SET). Warto przypomnieć, że w akcesorach SET występuje niejawnie zadeklarowana zmienna przechowująca wartość przypisywaną do indeksatora.
Indeksery pozwalają na indeksowanie obiektów w taki sam sposób jak ma to miejsce w tablicach. Kiedy definiujemy indeksery dla klas, zachowuje się ona w podobny sposób do wirtualnej tablicy. Można uzyskać dostęp do instancji tej klasy przy użyciu operatora dostępu do tablicy, tj. ([]).
Składnia definicji jednowymiarowego indeksera:
1 2 3 4 5 6 7 8 9 10 11 |
typ_elementu this[int index] { get { // zwracanie wartości wskazanej przez indeks } set { // ustawienie wartości wskazanej przez indeks } } |
Używanie indekserów
Deklaracje zachowania indeksera możemy porónać do właściwości. Deklarując indekser również będziemy używać properties get oraz set. Niemniej jednak, właściwość zwróci lub ustawi dane dla konkretnego elementu, podczas gdy masze indeksery mają za zadanie zwrócić lub ustawić konkretną wartość z instancji obiektu. Innymi słowy, zbiór danych zostaje podzielony na mniejsze części a indekser zwraca lub ustawia wartości dla poszczególnych elementów.
Definiowanie właściwości składa się z określenia nazwy. W przypadku indekserów nie używamy nazwy, ale słowa kluczowego this, które wskazuje na instancje obiektu.
Zwróć uwagę na poniższy przykład, który w przyjaźniejszy sposób pozwoli nam poznać działanie indekserów:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
using System; namespace Indexers { class Program { // names list private string[] nameList = new string[size]; // list size static int size = 10; static void Main(string[] args) { Program names = new Program(); names[0] = "BMW"; names[1] = "Pagani"; names[2] = "Audi"; names[3] = "Tesla"; names[4] = "Porsche"; for (int i = 0; i < size; i++) { Console.WriteLine(names[i]); } Console.ReadKey(); } // The class constructor fills the list with 'N.A' elements public Program() { for (int i = 0; i < size; i++) { nameList[i] = "N.A"; } } // Indekser public string this[int index] { get { string temp; if (index >= 0 && index <= size - 1) temp = nameList[index]; else temp = ""; return temp; } set { if (index >= 0 && index <= size - 1) nameList[index] = value; } } } } |
Przeciążanie indekserów
Czy Indeksery możemy przeciążąć?
Oczywiście, indeksery możemy rónież przeciążać. Indeksery mogą być również zdefiniowane z wieloma parametrami a każdy z parametrów może być innego typu. Do Indekserów nie musimy przypisywać tylko typów całkowitych. W języku C# dopuszczane jest, aby indeksery były innymi typami, np. string.
Poniższy przykład pokazuje sposób użycia indekserów przeciążonych:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
using System; namespace OverloadedIndexers { class Program { // names list private string[] nameList = new string[size]; // list size static int size = 10; static void Main(string[] args) { Program names = new Program(); names[0] = "BMW"; names[1] = "Pagani"; names[2] = "Audi"; names[3] = "Tesla"; names[4] = "Porsche"; // using an indexer with a parameter of type int for (int i = 0; i < size; i++) { Console.WriteLine(names[i]); } // use the index with a string type parameter Console.WriteLine(names["BMW"]); Console.ReadKey(); //Porsche //BMW //Pagani //Audi //Tesla // N.A // N.A // N.A // N.A // N.A // 2 } // The class constructor fills the list with 'N.A' elements public Program() { for (int i = 0; i < size; i++) { nameList[i] = "N.A"; } } // Indekser public string this[int index] { get { string temp; if (index >= 0 && index <= size - 1) temp = nameList[index]; else temp = ""; return temp; } set { if (index >= 0 && index <= size - 1) nameList[index] = value; } } public int this[string name] { get { int index = 0; while (index < size) { if (nameList[index] == name) return index; index++; } return index; } } } } |
Jak zawsze kod wrzucony będzie do GitHuba.
Podobało się? dajcie like’a 😉 lub piszcie i komentujcie.