Curiously Recurring Template Pattern (CRTP) in C#

Curiously Recurring Template Pattern (CRTP) in C#

When defining  a system’s architecture, we discover that there are several ways to achieve the same result and we have to evaluate the advantages that we can obtain by doing it in one way or another.

We encounter different design patterns and on this occasion I want to show CRTP, also known as F-bound polymorphism.

This pattern consists essentially in creating a base class using a Generic Type as a template.

Before presenting an actual implementation example, let’s see a classic architecture with inheritance and then understand which limitation this might have, in order to implement CRTP:

inheritanceexample1

As you can see it’s a quite simple inheritance case, with an abstract base class that defines an abstract operation and after that the classes that inherit from this base class implement the operation.

This operation should be invoked as follows:

CRTPinvocationexample2

As described in the previous image, to be able to assign the result of invoking the method MapOnlyPrimitives() an explicit cast is needed and at this point is where we ask questions:

Is this the only way to do this? Is there any way in an inheritance context in which invoking MapOnlyPrimitives () returns precisely an object of the resulting type class and not the base class?

It makes sense doesn’t it? We are specifically invoking the method from an instance of the resulting class, therefore the most suitable in this case would be to return an object of the resulting class and not of the base class.

The solution is to implement CRTP and with few modifications to the architecture previously described, let’s see how:

CRTPexample3 (2)

We set up in the base class a generic type T, which remains as if it was a template where we can place the signatures of the operations involving this generic type T.

When building the resulting classes, these will continue to inherit from the base class, but this time specifying in each case which is the type that will assume the generic class T in the base class.

By then, the invocation can now be as follows:

inheritanceinvocationexample4

As we initially said, there are multiple ways to accomplish the same result. To select the most correct architecture for our system we have to evaluate the pros and the cons of the different choices.

Perhaps the requirement to implement something like this is not very noticeable in the example given. In my personal opinion it is an elegant solution, but beyond that there are cases where many casts are needed and implementing something alike this example can make it quite easier.

Sources and further information:

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

http://zpbappi.com/curiously-recurring-template-pattern-in-csharp



 

Curiously Recurring Template Pattern (CRTP) en C#

A la hora de definir la arquitectura de un sistema nos encontramos con que existen varios caminos para conseguir un mismo resultado y tenemos que evaluar las ventajas que nos puede brindar el hacerlo de una u otra forma.

Es así que nos topamos con distintos patrones de diseño y en esta oportunidad les quiero mostrar CRTP o también conocido como F-bound polymorphism.

Básicamente este patrón consiste en crear una clase base utilizando un Generic Type como plantilla.

Antes de mostrar un ejemplo concreto de implementación veamos una arquitectura clásica con herencia y de ahí ver qué limitante podría ésta tener, para querer implementar CRTP:

inheritanceexample1

Como podrán ver, es un simple caso de herencia, donde hay una clase base abstracta que define una operación abstracta y luego las clases que heredan de esta clase base implementan dicha operación.

La forma en que se invocaría esta operación sería algo así:

inheritanceinvocationexample4

Como se describe en la imagen anterior, para poder asignar el resultado de invocar al método MapOnlyPrimitives()​ es necesario hacer un casteo explícito  y aquí es donde nos planteamos:blo

¿Es esta la única forma de hacer esto? ¿Existe alguna manera en un contexto de herencia en la cual invocar a MapOnlyPrimitives() nos retorne justamente un objeto del tipo de la clase derivada y no de la clase base?

Tiene sentido ¿no? Después de todo nosotros justamente estamos invocando al método desde una instancia de la clase derivada, por ende lo más cómodo sería poder retornar en este caso un objeto de la clase derivada y no de la clase base.

La solución a esto es implementar CRTP y con unas pequeñas modificaciones a la arquitectura antes expuesta, vamos a ver cómo:

CRTPexample3 (2)

Lo que se hizo fue establecer en la clase base un tipo genérico T quedando esta primera como si fuese una plantilla donde podemos poner las firmas de las operaciones, involucrando a este tipo genérico T.

A la hora de establecer las clases derivadas, éstas van a seguir heredando de la clase base, pero esta vez especificando en cada caso cuál es el tipo que asumirá la clase genérica T en la clase base.

De esta manera, cuando el método MapOnlyPrimitives() es sobrescrito, puede hacerse utilizando el tipo de dato de la clase derivada ya que hemos especificado qué tipo va a asumir el genérico T para el caso de implementación de esa clase derivada.

Entonces la invocación ahora puede ser de la siguiente forma:

CRTPinvocationexample2

Como decíamos al principio, existen múltiples formas de llegar al mismo resultado. Y para decidir la arquitectura más correcta para nuestro sistema tenemos que poner en una balanza los pro y los contras de las distintas alternativas.

Tal vez en el ejemplo propuesto no se note mucho la necesidad de implementar algo así. A mi criterio personal es una solución elegante, pero más allá de eso hay casos en los que son necesarios muchos casteos y podría facilitar bastante implementar algo así.

Fuentes y más información:

https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

http://zpbappi.com/curiously-recurring-template-pattern-in-csharp

 

Share This