Читать книгу Programowanie funkcyjne w języku C#. Jak pisać lepszy kod - Enrico Buonanno - Страница 19

1.2.2 Elementy funkcyjne w C# 6 i C# 7

Оглавление

C# 6 i C# 7 nie są tak rewolucyjne jak C# 3, ale obejmują wiele drobniejszych elementów języka, które w sumie dają dużo większe możliwości i bardziej idiomatyczną składnię do funkcyjnego kodowania.

UWAGA Większość funkcji wprowadzonych w C# 6 i C# 7 oferuje lepszą składnię, ale nie nowe funkcje. Jeśli używacie starszej wersji C#, możecie stosować wszystkie techniki pokazane w tej książce (wymaga to tylko trochę więcej pisania). Jednak nowsze funkcje znacznie poprawiają czytelność, co sprawia, że programowanie w stylu funkcyjnym jest bardzie atrakcyjne.

Te elementy możemy zobaczyć w działaniu na poniższym listingu.

using static System.Math;

public class Circle

Używanie static umożliwia niekwalifikowany dostęp do elementów statycznych System.Math, jak PI i Pow

{

public Circle(double radius)

=> Radius = radius;

public double Radius { get; }

Automatyczna właściwość tylko do odczytu może zostać ustawiona tylko w konstruktorze

public double Circumference

=> PI * 2 * Radius;

public double Area

Właściwość z wyrażeniem

{

get

{

double Square(double d) => Pow(d, 2);

Funkcja lokalna to metoda zadeklarowana w innej metodzie

return PI * Square(Radius);

}

}

public (double Circumference, double Area) Stats

Składnia krotek w C# 7 z nazwanymi elementami

=> (Circumference, Area);

}

Listing 1.4 Funkcje C# 6 i C# 7 istotne dla FP

Import elementów statycznych za pomocą using static

Użycie deklaracji using static w C# 6 pozwala nam na import statycznych elementów klasy (w tym przykładzie klasy System.Math). W rezultacie, w tym przykładzie możemy wywołać elementy Math o nazwach PI i Pow bez dalszej przestrzeni nazw:

using static System.Math;

public double Circumference

=> PI * 2 * Radius;

Dlaczego jest to ważne? W FP wolimy funkcje, których zachowanie zależy tylko od ich argumentów wejściowych, gdyż możemy wnioskować na ich temat i testować je oddzielnie (w odróżnieniu od instancji metod, których implementacja zwykle wpływa na instancje zmiennych). Te funkcje są implementowane jako statyczne metody w C#, zatem biblioteka funkcyjna w C# będzie się składać przede wszystkim z metod statycznych.

Deklaracja using static pozwala nam na łatwiejsze użycie takich bibliotek i choć nadużywanie może prowadzić do zanieczyszczenia przestrzeni nazw, to rozsądne wykorzystanie pozwala tworzyć czysty, czytelny kod.

Łatwiejsze typy niemutowalne z automatycznymi właściwościami typu tylko do odczytu

Gdy deklarujemy automatyczne właściwości tylko do odczytu, jak Radius, kompilator domyślnie deklaruje pole zapasowe (backing field) readonly. W wyniku tego właściwościom tym można przypisać wartość tylko w konstruktorze lub w miejscu zadeklarowania:

public class Circle

{

public Circle(double radius)

=> Radius = radius;

public double Radius { get; }

}

Automatyczne właściwości tylko do odczytu ułatwiają definicje typów niemutowalnych, które zobaczymy bardziej szczegółowo w rozdziale 9. Klasa Circle pokazuje, że ma tylko jedno pole (pole pomocnicze w Radius), które jest readonly, więc po jego utworzeniu Circle nie może go już zmienić.

Bardziej zwięzłe funkcje z użyciem wyrażeń w treści (expression-bodied)

Własność Circumference jest deklarowana za pomocą treści wyrażeniowej wprowadzonej przez =>, zamiast zwykłej treści instrukcji w {}:

public double Circumference

=> PI * 2 * Radius;

Zauważmy, jak jest to zwięzłe w porównaniu z własnością Area!

W FP mamy tendencję do pisania wielu prostych funkcji, często jednowierszowych, a następnie składamy z nich bardziej złożone funkcje. Metody jako wyrażenia pozwalają nam na wykonanie tego przy minimalnym narzucie składniowym. Jest to szczególnie widoczne, gdy chcemy napisać funkcję, która zwraca funkcję – coś co będziemy często robić w tej książce.

Składnia z wyrażeniami w treści została wprowadzona w C# 6 dla metod i właściwości, a potem została uogólniona w C# 7 na konstruktory, destruktory, gettery oraz settery.

Funkcje lokalne

Pisanie wielu prostych funkcji oznacza, że wiele funkcji będzie wywoływanych tylko z jednego miejsca. C# 7 pozwala nam na jawne zadeklarowanie metod w zakresie innych metod. Na przykład metoda Square jest zadeklarowana w zakresie funkcji zwracającej wartość Area:

get

{

double Square(double d) => Pow(d, 2);

return PI * Square(Radius);

}

Lepsza składnia dla krotek

Lepsza składnia dla krotek jest jedną z najważniejszych cech języka C# 7. Pozwala nam na łatwe tworzenie i używanie krotek, a co najważniejsze, na przypisywanie znaczących nazw ich elementom. Na przykład własność Stats zwraca krotkę typu (double, double) i podaje znaczące nazwy, poprzez które mamy dostęp do jej elementów:

public (double Circumference, double Area) Stats

=> (Circumference, Area);

Krotki są ważne w FP ze względu na tendencję do podziału zadań na bardzo małe funkcje. Może się okazać, że będziemy mieli typ danych, którego jedynym celem będzie przechwycenie informacji zwracanej przez jedną funkcję, która z kolei jest oczekiwana na wejściu innej funkcji. Niepraktyczne jest definiowanie dedykowanych typów dla takich struktur, które nie odpowiadają żadnym istotnym abstrakcjom z danej domeny. Tu właśnie jest miejsce na krotki.

Programowanie funkcyjne w języku C#. Jak pisać lepszy kod

Подняться наверх