Zainspirowany kolegami z pracy (ale jesteśmy inspirujący 🙂 ) postanowiłem napisać o dynamic jako elemencie fajnym do napisania ładnego kodu typu Type matching (czyli pattern matching po typie :)). Po tym przydługim wstępie -> Do Kodu!

Załóżmy taki wesoły kod który nie rozwiązuje żadnego typowego problemu. Po prostu w zależności od typu podanego na wejściu zwraca on odpowiedni int. Ten kod jest specjalnie uproszczony i źle napisany, bo widać, że użyto tutaj podwójnego rzutowania. Najpierw sprawdzamy is, a potem rzutujemy. Specjalnie napisany w ten sposób by zajmował jak najmniej miejsca. Co do rzutowania to powinno być bardziej napisane w ten sposób:

Ale ponieważ korzystamy z kodu uproszczonego, to jego użycie wygląda tak:

Co najważniejsze – kompilator nie zgłasza żadnych problemów, wszystko działa jak ta lala, a kod LiczNormalnie.Licz(1.1) zwraca, jak łatwo się domyśleć – 0.

To samo można napisać używając dynamic, rozrzucając odpowiedzialności do poszczególnych funkcji i rezygnując z rzutowań.

Generalnie kod zajął jedną linijkę więcej :(. Za to jak ładnie wygląda :). Czystość zapisu to jeden z największych plusów dynamic.

A powyżej mamy użycie tej funkcji. Tylko tutaj w linii 3 kodu dostaniemy błąd. Jest to jedna z najfajniejszych wiadomości. Kompilator poinformuje nas, że nie wzięliśmy tego elementu pod uwagę. Co prawda dostaniemy wiele mówiący StackOverflowException, ale jednak dostaniemy.

Gdy przesiądziemy się z typów prostych na bardziej złożone, np takie:

Czas nadal stoi po stronie dynamic. To rozwiązanie oprócz czytelności jest co najmniej 2 razy szybsze do zwykłego.

Testy czasu wykonywałem za pomocą Stopwatch, a klasy testowałem w aplikacji konsolowej. Może jest to jakieś rozwiązanie problemu Ayende?

 

==== Edit ====

Po wskazaniu znów przez Revisa (dzięki!) tego, że przykład nie pokazuje sensu użycia, poniżej taki wskazujący po co to wszystko. Bez zbędnego “pitu pitu” to się nie “skomplikuje”:

Jak usuniemy linię EatSweetie.Eat(iceCream) -> wszystko zadziała bez problemu. Błąd to oczywiście “Sweetie is not assignable to parameter IceCream”. Gdy dodamy kolejne Sweeties (Cookie, Chocolate) to rozwiązanie oparte na przeciążeniu nazw metod nie zadziała. Za to dynamic świetnie daje sobie z tym radę.  Mam nadzieję, że to wystarczająca odpowiedź na zadane pytanie?

 

6 Replies to “Type matching – dynamic w pattern matchingu.

  1. Pingback: dotnetomaniak.pl
  2. Cały QueryGenerator mam tak napisany (coś co z dowolnej części abstraktu zapytania sql zwraca sql odpowiedniego dla platformy bazodanowej).
    Chwaliłem się kiedyś SM (odnośnie kolegów z pracy).

    Oprócz zalet, zauważyłem 2 wady:
    1. Co oczywiste, o pewnych niedopasowaniach typów dowiesz się dopiero w runtime’ie.
    2. Zauważyłem, że pierwsze użycie dynamic w AppDomain kosztuje ok 1s. Potem już błysk ciupagi.

    Co dalej? Dalej postanowiłem tą cześć kodu napisać w F#, bo wygląda, że się bardziej do tego nadaje – z pattern matchingiem na czele.

    PS. Ciekawe czy sobie Sauron poradzi w kompilacją F#

    1. Sauron jest wszechpotężny… Nie zapominaj o tym. Nazwa serwera zobowiązuje 🙂
      F# to dobry pomysł, zresztą chyba idealny do BI, Machine Lerning i innych.

  3. Nie bardzo rozumiem co to ma wspólnego z dynamic. Nie lepiej tą jedną metodę która rekurencyjnie się zapętla (StackOvertlowException) usunąć i polegać już tylko na przeciążeniach nazw metod pomiędzy string, int i bool? Wtedy błąd dla 1.1 dostaniemy już na etapie kompilacji. Dynamic tutaj tylko ukrywa problem przechwytując wszystko co nie pasuje do już zaimplementowanych typów.

    1. Nie widać tego, bo przykład jest zbyt banalny. Chodziło tylko o użycie, ale już dodaję moment w którym widać sens użycia.

Dodaj komentarz

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