Koniec z nullem! – nowe typy referencyjne w C# 8.0

12 stycznia 2020 o 11:36 Autor:

Być może dla niektórych nadal to jest zaskoczenie ale języki programowania też dostają nowe wersji. I nie inaczej jest z językiem C#, który niedawno zagościł u nas w wersji 8.0.

Przyniósł nam on kilka ciekawych zmian, a jedną z nich jest ta, która idzie na wojnę z nullami. Co prawda seria o zmianach w C# dopiero powstaje ale już dzisiaj chcę opisać właśnie tą bo myślę, że będzie dla Ciebie ciekawa. Chociażby dlatego, że pokaże pewne podejście do pisania kodu.

Czego chcesz? Nie mam!

W języku C# większość typów na jakich operujemy jest typami referencyjnymi. Bo poza takimi typami jak int czy bool, wszystkie typy bazujące na klasach albo chociażby typ string referencyjne. Oznacza to, że przechowują jakiś obiekt. Albo go nie przechowują bo go nie mają.

Zawsze kiedy korzystamy z jakiejś zmiennej, która powinna zawierać obiekt to musimy być pewni, że ten obiekt tam jest. Inaczej dostaniemy w trakcie działania programu wyjątek NullReferenceException.

I najgorszy w tym wszystkim jest fakt, że ten wyjątek poleci dopiero kiedy zaczniemy klikać w program. Bo to oznacza, że jeżeli popełniliśmy błąd to dowiemy się o nim dopiero po uruchomieniu i trafieniu akurat na ten fragment. Testy jednostkowe niekoniecznie go wyłapią bo może to być np. problem z rejestracją dostępnych klas. Nowoczesne narzędzia, jak np. ReSharper, potrafią podpowiedzieć, że gdzieś nie sprawdzamy czy coś na pewno nie jest nullem. Ale nie wszystkie przypadki zdołają zauważyć.

Ostatecznie kończymy nieraz z kodem, który co chwilę ma wstawki typu:

if (value == null)
{
    // do something
}

Które zaśmiecają nasz kod. A ponieważ typy referencyjne mogą niemieć tej referencji to bez naprawdę dobrej kontroli każdego fragmentu kodu nie mamy szans tego w 100% wyeliminować.

Nie wolno przyjść z pustymi rękami

Przynajmniej tak było do tej pory. Bo wszystko popsuła wersja 8.0 języka C#. Wprowadziła ona dla typów referencyjnych ten sam mechanizm, który mamy od dawna przy typach wartościowych.

Chodzi mianowicie o założenie, że od teraz typy referencyjne również nie mogą przyjmować nulla. W C# 8.0 nie zrobisz niepostrzeżenie czegoś takiego:

x.Name = null;

Bo dostaniesz ostrzeżenie, że robisz krzywdę ludzkości. Co prawda programiści Microsoftu wiedzieli, że to jest breaking change więc w tym momencie to sprawdzanie jest domyślnie wyłączone. Ale jeżeli tylko korzystasz z nowej wersji .NETa to polecam Ci je włączyć i przekonać się jak wiele takich operacji wykonujesz.

Od tej pory chcąc móc ustawić jakieś pole na null musisz to jasno zakomunikować. Służy do tego ten sam operator co w przypadku typów wartościowych. Jest nim znak zapytania po nazwie typu:

class Fields
{
    public MyClass? Nullable { get; set; }
    public MyClass NotNullable { get; set; }
}

W powyższym przypadku do pola pierwszego możesz przypisać null. Przy drugim polu zostaniesz upomniany, że coś jest nie tak bo autor klasy nie zgodził się na nulle.

Dzięki temu statyczna analiza kodu już na etapie kompilacji ale wcześniej będzie mogła poinformować, że robisz coś nie tak. Bo jeżeli typ nie jest oznaczony jako nullowalny to mamy sygnał, że autor takiego pola nie przewidział, że może ono być nullem i prawdopodobnie gdzieś aplikacja przez to rzuci wyjątek. Z drugiej strony jeżeli działamy według zasady „trust me, I’m engineer” to możesz wyłączyć ostrzeżenie i działać jak dawniej. Ale wtedy nie mów, że boli jak przypadkiem aplikacja nie zadziała na produkcji przez NullReferenceException.

Jak żyć?

Jeżeli nie chcemy mieć w kodzie użytych nulli, a jednocześnie mamy sytuacje kiedy niekoniecznie wartość będzie dostępna to mamy do wyboru inne opcje. Nie będę ich tutaj dokładniej opisywał. Ale warto żebyś o nich poczytał.

Tymi opcjami są np. typy Optional albo zastosowanie wzorca NullObject. Są one do siebie bardzo podobne.

Jeżeli chodzi o typ Option/Optional to jego implementacja jest np. częścią biblioteki language-ext dostępnej tutaj:

https://github.com/louthy/language-ext#option

O własnej implementacji takiego typu poczytasz np. tutaj:

http://codinghelmet.com/articles/custom-implementation-of-the-option-maybe-type-in-cs

W temacie NullObjectów możesz znaleźć co nieco chociażby na tej stronie:

https://dev.to/balazsbotond/dealing-with-nothing-in-c—the-null-object-pattern-2e9c

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *