Ostatnio patrzyłem na język F # i chociaż nie zamierzam w najbliższym czasie przeskoczyć przez barierę, zdecydowanie podkreśla niektóre obszary, w których C # (lub obsługa bibliotek) może ułatwić życie.
W szczególności myślę o możliwości dopasowania wzorców w F #, która pozwala na bardzo bogatą składnię - znacznie bardziej wyrazistą niż bieżące odpowiedniki przełącznika / warunkowe C #. Nie będę próbował podawać bezpośredniego przykładu (mój F # nie jest do tego przystosowany), ale w skrócie pozwala:
- dopasuj według typu (ze sprawdzaniem pełnego pokrycia dla związków rozłącznych) [uwaga: to również określa typ zmiennej powiązanej, dając dostęp do elementu członkowskiego itp.]
- dopasować według predykatu
- kombinacje powyższych (i być może kilka innych scenariuszy, których nie znam)
Chociaż byłoby cudownie, gdyby C # ostatecznie pożyczył [ahem] część tego bogactwa, w międzyczasie przyglądałem się temu, co można zrobić w czasie wykonywania - na przykład dość łatwo jest połączyć niektóre obiekty, aby umożliwić:
var getRentPrice = new Switch<Vehicle, int>()
.Case<Motorcycle>(bike => 100 + bike.Cylinders * 10) // "bike" here is typed as Motorcycle
.Case<Bicycle>(30) // returns a constant
.Case<Car>(car => car.EngineType == EngineType.Diesel, car => 220 + car.Doors * 20)
.Case<Car>(car => car.EngineType == EngineType.Gasoline, car => 200 + car.Doors * 20)
.ElseThrow(); // or could use a Default(...) terminator
gdzie getRentPrice to Func <Vehicle, int>.
[uwaga - być może Switch / Case to niewłaściwe terminy ... ale pokazuje ideę]
Dla mnie jest to o wiele jaśniejsze niż ekwiwalent z użyciem powtórzonego if / else lub złożonego trójskładnikowego warunku (co staje się bardzo nieuporządkowane w przypadku nietrywialnych wyrażeń - mnóstwo nawiasów). Pozwala również uniknąć wielu rzutów i umożliwia proste rozszerzenie (bezpośrednio lub metodami rozszerzania) na bardziej szczegółowe dopasowania, na przykład dopasowanie InRange (...) porównywalne z VB Select ... Przypadek "x To y " stosowanie.
Po prostu próbuję ocenić, czy ludzie uważają, że konstrukcje takie jak powyżej dają wiele korzyści (przy braku obsługi języka)?
Uwaga dodatkowo, że grałem z 3 wariantami powyższego:
- wersja Func <TSource, TValue> do oceny - porównywalna do złożonych trójskładnikowych instrukcji warunkowych
- wersja Action <TSource> - porównywalna do if / else if / else if / else if / else
- wersja Expression <Func <TSource, TValue >> - jako pierwsza, ale do wykorzystania przez dowolnych dostawców LINQ
Ponadto użycie wersji opartej na wyrażeniach umożliwia ponowne zapisywanie drzewa wyrażeń, zasadniczo umieszczając wszystkie gałęzie w jednym złożonym wyrażeniu warunkowym, zamiast używać wielokrotnego wywołania. Nie sprawdzałem ostatnio, ale w niektórych wczesnych kompilacjach Entity Framework wydaje mi się, że jest to konieczne, ponieważ nie bardzo lubił InvocationExpression. Pozwala również na bardziej wydajne użycie z LINQ-to-Objects, ponieważ pozwala uniknąć powtarzających się wywołań delegatów - testy pokazują dopasowanie podobne do powyższego (przy użyciu formularza Expression) działające z tą samą prędkością [w rzeczywistości nieznacznie szybsze] w porównaniu z równoważnym C # złożona instrukcja warunkowa. Aby zapewnić kompletność, wersja oparta na Func <...> zajęła 4 razy więcej czasu niż instrukcja warunkowa C #, ale nadal jest bardzo szybka i jest mało prawdopodobne, aby była głównym wąskim gardłem w większości przypadków użycia.
Z zadowoleniem przyjmuję wszelkie przemyślenia / wkład / krytykę / itp. Dotyczące powyższego (lub możliwości bogatszej obsługi języka C # ... mam nadzieję ;-p).
switch-case
oświadczenia. Nie zrozum mnie źle, myślę, że ma swoje miejsce i prawdopodobnie będę szukał sposobu na wdrożenie.