Null-check w C# przy użyciu discards

W ubiegłym roku pisałem o bezpiecznym null-checku w C# przy użyciu słowa kluczowego is, który według mnie powinien być stosowany wszędzie gdzie jest to możliwe. Dziś dla odmiany konstrukcja, która jest bardziej ciekawostką językową niż czymś (co ja osobiście) chciałbym znaleźć w kodzie. Problemem jest przede wszystkim ograniczona funkcjonalność, ale także czytelność i interpretacja konstrukcji szczegolnie przez osoby początkujące, albo takie które nie są na bieżąco z językiem. Zobaczmy zatem jak ten twór wygląda

 


public void MyMethod(string parameter)
{
    _ = parameter ?? throw new ArgumentException("Parameter cannot be null");
}

 

Powyższy zapis jest kompilowany do poniższego kodu:

 


    public void MyMethod(string parameter)
    {
        if (parameter == null)
        {
            throw new ArgumentException("Parameter cannot be null");
        }
    }

 

Warto wyjasnić czym jest podkreślnik i dlaczego nie poprzeda go deklaracja typu skoro wygląda to na zmienną lokalną. Sam zapis podkreślnika jako nazwy zmiennej istnieje w C# jako konwencja od dosyć dawna i nazywa się discard. Przyjęło się nazywać tak zmienne, których intencjonalnie nie chcemy/nie powinniśmy używać w wybranym kontekście. Jeżeli kiedykolwiek miałeś/aś stycznośc z biblioteką Nancy to na pewno kojarzysz tą konstrukcję:

 


Get["/"] = _ => "Hello World!";

 

Co znajduje się pod _? W tym przypadku jest to jakaś zmienna typu dynamic. Nas jako użytkowników bilbioteki widząc taki zapis nie powinno zatem interesować po co ona się tam znajduje. Byc może jest póżniej używana do zbudowania jakiegoś drzewa wyrażeń, albo i nie. W tym przypadku who cares. Dodam jeszcze, że sam stosowałem tę konwecję w swoim projekcie Valit.

 

Od C# w wersji 7 discards są wspierane przez sam język i mogą zostać użyte w wielu sytuacjach m.in:

  • uzycia Tuple i dekonstrukcji obiektów
  • pattern matchingu
  • wywołaniach metod z parametrem out

Ponadto discardów możemy uzywać jako samodzielne byty pod warunkiem, że wcześniej w zasięgu scopa nie zadeklarowalismy zmiennej o nazwie _.

Kluczowe jest zatem rozróżnieine konwencji nazewniczej (jak przykład w Nancy) od rzeczywistego mechizmu języka. Ten kod to zwykła deklaracja zmiennej, której nadałem intencjonalnie nazwę _, aby podkreślić że nie obchodzi mnie dalej w metodzie:

 


    public void MyMethod(string parameter) 
    {
        var _ = 2;        
    }

    // KOMPILUJE SIE DO:

    public void MyMethod(string parameter)
    {
        int num = 2;
    }

 

Natomiast w tym przypadku używam discarda wspieranego przez kompilator, który optymalizuje konstrukcję o brak alokacji:

 


    public void MyMethod(string parameter) 
    {
        _ = 2;        
    }

    // KOMPILUJE SIE DO:

    public void MyMethod(string parameter)
    {
    }

 

Posiadając tą wiedzę wiesz już dlaczego dziwny if z początku wpisu nie posiada deklaracji typu. Jest to discard wpierany przez język gdzie intencjonalnie wskazujemy, że nie interesuje nas wartość lewego operandu. Chcemy jedynie rzucić wyjątek jeżeli zmeinna parameter jest null.

 

Tyle na dziś. Jak wspomniałem bardziej ciekawostka niż praktyczny tip produkcyjne, ale można traktować jako killer na rozmowach rekrutacyjnych 😀 Zachęcam do zapoznania się z innymi użyciami samych discardów, bo zdecydowanie warto!

You may also like...