Wprowadzenie

Jest to trzeci z serii artykułów dotyczących nowych funkcjonalności języka C# 8.0. Pierwszy artykuł dotyczył interpolacji ciągów. Kolejny skupiał się na typach docelowych. Jeżeli przegapiliście te artykuły zapraszam do zapoznania się z ich treścią:

W tej części skupimy się na operatorze binarnym ^. Do tej pory używany był jako operator logiczny(XOR) dla typów boolean oraz jako operator bitowy XOR dla typów bitowych oraz integralnych(short, ushort, int, etc.). W C# 8.0 znajdzie jednak nowe zastosowanie.

C# 8.0

Kod struktury indeksu (Index struct) jest dostępny na portalu GitHub pod adresem: GitHub. Analiza kodu pozwala stwierdzić, że jest to dość prosta struktura, która przechowuje wartość całkowitą (int) wewnątrz wartości logicznej (boolean) w celu określenia czy odliczanie powinno zaczynać sie od końca. Takie wyjaśnienie brzmi nieco skomplikowanie ale pozwala na uzyskanie dostępu o wiele łatwiej niż w poprzednich wersjach języka. Możemy w bardzo prosty sposób zapisać taką liczbę w typie indeksu (Indeks) zamiast liczby całkowitej. Taki zapis jasno definiuje cel jej użycia i pozwala uniknać niewłaściwego użycia tej zmiennej.

Dotychczas myśleliśmy od samego początku o próbie uzyskania dostępu do określonej wartości znajdującej się na określonym miejscu (indeksie) tablicy. Chcąc dostać się do ostatniego elementu naszej tablicy, której rozmiar był znany, zwykle używaliśmy liczby całkowitej (hardcoded):

int[] array = new int[] { 1, 2, 3, 4, 5 };
var num = array[4];
lub korzystaliśmy z nieco bardziej eleganckiego zapisu:
int[] array = new int[] { 1, 2, 3, 4, 5 };
var num = array[array.Length - 1];

Powyższy zapis byłby również używany, gdyby rozmiar tablicy nie był znany w momencie kompilacji. Jest to preferowany sposób zapisu ponieważ wyliczenia liczbami wpisanymi na sztywno nigdy nie są bezpieczne i często mogą doprowadzić do nieczekiwanych błędów. Taki zapis pozwala również w dużo prostszy sposób zwrócić np. element przedostatni.

Korzystając jednak ze struktury indeksu możemy łatwo stworzyć typ indeksu, przechowywać go i ponownie wykorzystac wedle uzniania nie naruszająć zasady DRY (Don’t repeat yourself):

Index lastItem = new Index(4, false);
int[] array = new int[] { 1, 2, 3, 4, 5 };
var num = array[lastItem];
Warto jednak odwrócić zapis korzystając ze zmiennej fromEnd, aby lepiej zobrazować w kodzie nasze intencje – chcemy pobrać ostatni element z tablicy nie znając jej rozmiaru w trakcie kompilacji:
Index lastItem = new Index(1, true);
int[] array = new int[] { 1, 2, 3, 4, 5 };
var num = array[lastItem];
Jedną rzeczą, którą należy zapamietać jest to, że licząc od końca nie mamy indeksu 0. Zachowanie to jest podobne do zapisu Length - liczba, gdzie liczba jest wartością, której użyjemy w zapisie struktury indeksu.

Gdzie jednak jest miejsce na operator ^? Operator ten jest skrótem powyższego zapisu pozwalającego na wyszukanie ostatniego elementu tablicy nie znając jej rozmiaru w trakcie kompilacji. Spójrz proszę na dwa poniższe przykłady (są one identyczne):

Index lastItem = new Index(1, true);
int[] array = new int[] { 1, 2, 3, 4, 5 };
var num = array[lastItem];

Index lastItem = ^1;
int[] array = new int[] { 1, 2, 3, 4, 5 };
var num = array[lastItem];
oraz
Index secondLastItem = new Index(2, true);
int[] array = new int[] { 1, 2, 3, 4, 5 };
var num = array[secondLastItem];

Index secondLastItem = ^2;
int[] array = new int[] { 1, 2, 3, 4, 5 };
var num = array[secondLastItem];

Podsumowanie

W tym krótkim artykule dowiedzieliście się jak można używać struktury indeksu oraz poznaliście nowe zastosowania dla starego operatora: ^. C# 8.0 wprowadza wiele istotnych zmian, które warto prześledzić i wprowadzić (wedle uznania) do swoich codziennych rytuałów programowania.