CRTP

Typy rekurencyjne w .NET

Intro

C# 8.0 został niedawno opublikowany, jednak w dzisiejszym poście chcę napisać o funkcjonalności z C# 2.0. Wtedy to właśnie firma Microsoft wprowadziła typy generyczne. Każdy wie, każdy używa, ale cz próbowałeś kiedykolwiek napisać coś takiego:

class A<T> where T : A<T> { }

Ok, stop… Masz teraz 2 opcje

  1. Kontynuuj, ale nie ma zagadki
  2. Zamknij kartę, porozmyślaj i wróć tutaj

Ten post należy do serii Podejrzane typy.

Spróbuj dotknąć

Odpowiedzmy na pytanie:

Jak mogę stworzyć instancję obiektu A?

Hmm… Spróbujmy!

var a = new A<A<A<...>>>();

To nie wygląda jak droga do sukcesu.

Wprowadźmy zmienną pomocniczą B:

B = A<A<A<...>>>

To oznacza, że:

A<B> = A<A<A<...>>>

Czyli:

B = A<A<A<...>>> = A<B>

Ostatecznie:

B = A<B>

Wspaniale, ale co to oznacza? Nie mogliśmy stworzyć obiektu typu A bezpośrednio, ale czy w powietrzu nie unosi się właśnie woń dziedziczenia?

class B : A<B> { }

Wow! Kompiluje się! Nawet możemy stworzyć obiekt B za pomocą operatora new:

var b = new B();

Przyjrzyj się z bliska

Co się właśnie stało? Co stworzyliśmy? Musisz przyznać, że definicja klasy A jest dziwna interesująca.

Najwyższy czas na drugą zagadkę:

Zakładając poniższą definicję

class B : A<X> { }

, czy typ X zawsze musi być równy B?

Niestety odpowiedź brzmi… NIE. Poniżej 2 definicje typu X, który powodują, że powyższy kod się kompiluje:

class X : B { }
class X : A<X> { }

Jeśli znasz inne definicje typu X, to śmiało podziel się nią w komentarzu!

A dlaczego ze smutkiem napisałem, że nie zawsze X musi być tożsamy B? Ano dlatego, że w przeciwnym przypadku mielibyśmy na tacy w .NET Curiously Recurring Template Pattern (CRTP).

Wzorzec ten byłby przydatny w implementacji FluentApi oraz narzucaniu implementowania Api o specyficznych typach. Więcej ciekawych przykładów można znaleźć poście Curiously Recurring Template Pattern (CRTP) in C#.

Konstrukcja z początku tego posta spotkała się z krytyką ze strony Erica Lipperta, z którą można zapoznać się w jego poście Curiouser and curiouser. Główne zarzuty to fakt, że nie jest to poprawna implementacja CRTP (co wykazaliśmy na dwa sposoby również i w tym poście), oraz został zauważony fakt, że taki kod jest trudny w analizie przy pierwszym spotkaniu (czego pewnie doświadczyłaś/eś w pierwszym akapicie).

Niemniej jako zagadka i rozrywka umysłowa sprawdza się znakomicie 🙂

About the author

Programista lubiący ten fach. Połączenie perfekcjonisty i skauta z odrobiną eksperymentatora. Pracował dla dużych i małych, polskich i zagranicznych, prywatnych i publicznych podmiotów. Miał również przyjemność opiekować się praktykantami w jednej z poprzednich firm, jak również prowadzić ćwiczenia na Politechnice Warszawskiej, której jest dumnym absolwentem.

Leave a Reply

Your email address will not be published. Required fields are marked *