Curiously Recurring Template Pattern in C#

Posted by : on

Category : C#

What is the Curiously Recurring Template Pattern

In OOP when we use inheritance, a child class inherits data and behaviours from its parent. Sometimes though we may find ourselves in a situation that we need to know the type of the child class that called a method.

For example we may have a copy method in the parent that returns a copy of our object, that gets inherited by the child classes. We want this method to return a copy that is the type of the child and not the type of the parent.

The Curiously Recurring Template Pattern is useful for those kinds of situations.

How to implement it in code

The Curiously Recurring Template Pattern in C# makes use of generics. Its name comes from C++ that has templates that are the equivalent of C# generics. To use it, we define a parent class like this:

public abstract class Foo<T> where T : Foo<T>

This syntax may seem weird at first glance, so here’s the explanation:

This class (Foo) uses a generic T, which also derives from (Foo). This way, we know that T, is also of type (Foo) and that allows us to be able to know some of the T’s methods and data. The methods that are defined in (Foo).

An example

Let’s see an example in code to make this clearer. At first let’s suppose that we have the parent Unit class that doesn’t implement CRTP:

public abstract class Unit
{
   public abstract int AttackDamage { get; set; }
   public abstract void Attack();
   public abstract Unit MirrorImage();
}

and two children:

public class SmallUnit : Unit
{
   public sealed override int AttackDamage { get; set; }
   public sealed override void Attack() => Console.WriteLine($"I am a small unit that attacked for {AttackDamage}");
   public sealed override Unit MirrorImage() => new SmallUnit { AttackDamage = AttackDamage };
}

public class BigUnit : Unit
{
   public sealed override int AttackDamage { get; set; }
   public int SpellDamage { get; set; }
   public sealed override void Attack() => Console.WriteLine($"I am a big unit that attacked for {AttackDamage}");
   public sealed override Unit MirrorImage() =>
      new BigUnit
      {
         AttackDamage = AttackDamage,
         SpellDamage = SpellDamage
      };
   public void CastSpell() => Console.WriteLine($"I am a big unit that cast a spell for {SpellDamage}");
}

without the CRTP if we create two units:

Unit unit= new BigUnit
{
   AttackDamage = 5,
   SpellDamage = 6
};
Unit unit2= new SmallUnit 
{ AttackDamage = 5 };

and call:

var mirror = unit.MirrorImage();

then mirror is of type Unit. The only way to call the BigUnit’s CastSpell method would be through casting:

(mirror as BigUnit)?.CastSpell();

The null check here is important, because if we had tried the same with the unit2 without the check, our code would throw.

Imagine having a parent class with many different children and having to cast every time each one of them, so that we can use the child’s specific methods.

The CRPT solves that problem by allowing our MirrorImage method to return the correct type each time. First let’s see the implementation of the parent class:

public abstract class UnitCrtp<T> where T : UnitCrtp<T>
{
   public abstract int AttackDamage { get; set; }
   
   public abstract void Attack();
   
   public T MirrorImage() => Copy();
   protected abstract T Copy();
}

Now the return type of MirrorImage is T, so by implementing the children like this:

public class SmallUnit2 : UnitCrtp<SmallUnit2>
{
   public sealed override int AttackDamage { get; set; }
   public sealed override void Attack() => Console.WriteLine($"I am a small unit that attacked for {AttackDamage}");
   protected sealed override SmallUnit2 Copy() => new() { AttackDamage = AttackDamage };
}

public class BigUnit2 : UnitCrtp<BigUnit2> 
{
   public sealed override int AttackDamage { get; set; }
   public int SpellDamage { get; set; }

   public sealed override void Attack() => Console.WriteLine($"I am a big unit that that attacked for {AttackDamage}");
   protected sealed override BigUnit2 Copy() =>
      new()
      {
         AttackDamage = AttackDamage,
         SpellDamage = SpellDamage
      };
   public void CastSpell() => Console.WriteLine($"I am a big unit that cast a spell for {SpellDamage}");
}

our MirrorImage method will return the child’s type, so the following is possible:

UnitCrtp<BigUnit2> bigUnitCrtp= new BigUnit2
{
   AttackDamage = 5,
   SpellDamage = 6
};
UnitCrtp<SmallUnit2> smallUnitCrtp= new SmallUnit2 { AttackDamage = 5 };

var mirrorCrtp = bigUnitCrtp.MirrorImage();
mirrorCrtp.CastSpell();

here the mirrorCrtp is of type BigUnit2 and this allows us to call BigUnit2’s specific methods without any casting.

Problems of CRTP

Although the Curiously Recurring Template Pattern is useful, it has two main problems:

  • It is not easy to understand if someone has never seen it before and is looking our code. The
public abstract class UnitCrtp<T> where T : UnitCrtp<T> 

line is probably confusing for someone that doesn’t know about the CRTP

  • It is not completely type safe. Someone could do by mistake:
public class SmallUnit3 : UnitCrtp<BigUnit2>
{
   public sealed override int AttackDamage { get; set; }
   public sealed override void Attack() => Console.WriteLine($"I am a small unit that attacked for {AttackDamage}");
   protected override BigUnit2 Copy() =>  new() { AttackDamage = AttackDamage };
}

this creates the problem that the SmallUnit3 object will return a BigUnit2 object. We, or whoever uses our code will have to remember that the generic parameter has to be the child class.

Conclusion

As with all patterns, before using the Curiously Recurring Template Pattern someone has to weight the pros and cons and decide what is best for his specific situation, the readability and the extensibility of his code. Despite its problems, this is another, not so well known, tool in our toolbox.

Thank you for reading and as always if you have any questions or comments you can use the comments section or contact me directly via the contact form or by email, also if you don’t want to miss any of the new blog posts, you can always subscribe to my newsletter or the RSS feed.


About Giannis Akritidis

Hi, I am Giannis Akritidis. Programmer and Unity developer.

Follow @meredoth
Follow me: