Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# generics: what's the point of the "X<T> where T: X<T>" generic type constraint?

Tags:

c#

generics

Reading a book: NHibernate 3: Beginners guide I found a fragment that made me curious:

Time for action – Creating a base entity

(...)

  1. Add a new class to the folder Domain of the project and call it Entity. Make the class abstract and generic in T. Your code should look similar to the following code snippet:
 using System;

 namespace OrderingSystem.Domain
 {
     public abstract class Entity<T> where T : Entity<T>
     { }
 }

My question is: what is the point of the fragment where T : Entity<T>?

I understand that the where section can be applied to add constraints on the type T, but the code above looks like it would be never possible to instantiate such class (if it weren't abstract anyway).

like image 252
Paweł Bulwan Avatar asked Feb 13 '16 22:02

Paweł Bulwan


1 Answers

This is most likely meant to provide additional type safety for methods which return (or take in) an instance of the more derived type, saving the callers from having to cast the result to the more derived type.

abstract class Cloneable<T> where T : Cloneable<T>
{
    public abstract T Clone();
}

sealed class MyCloneable : Cloneable<MyCloneable>
{
    public override MyCloneable Clone()
    {
        return new MyCloneable();
    }
}

MyCloneable instance = new MyCloneable();
MyCloneable clone = instance.Clone();

EDIT

As per @siride's comment, this is known as the curiously recurring template pattern. Eric Lippert has written a great article on its application in C#:

https://blogs.msdn.microsoft.com/ericlippert/2011/02/03/curiouser-and-curiouser/

P.S. And just to illustrate what the above example would look like if you were to take away the generic constraint:

abstract class Cloneable
{
    public abstract Cloneable Clone();
}

sealed class MyCloneable : Cloneable
{
    public override Cloneable Clone()
    {
        return new MyCloneable();
    }
}

MyCloneable instance = new MyCloneable();
MyCloneable clone = (MyCloneable)instance.Clone(); // Note the cast.
like image 182
Kirill Shlenskiy Avatar answered Sep 27 '22 18:09

Kirill Shlenskiy