C# – Understanding Parameter Type Constraints

c++

I am looking at some code and I don't understand what a particular constraint means in the following class definition:

internal abstract class Entity<T> : Entity
    where T : Entity<T>
{ ... }

I don't understand what this implies about parameter type T.

Best Answer

This is similar to the "Curiously Recurring Template Pattern" (but it is NOT the same).

It can be used (among other things) to help constraint the parameter types of methods in a derived class to the same type as the derived class itself.

Here's an interesting blog post from Eric Lippert on this subject.

The main use of this is to force classes that derive from Entity<T> to implement some method that accepts a parameter of the same type as the deriving class.

In the following code sample, we declare in the Entity<T> class a method DoSomethingWithTheSameTypeAsMe() which accepts a parameter of type T.

Because of the generic constraint, this will force any classes that derive from Entity<T> to implement a version of DoSomethingWithTheSameTypeAsMe() which takes a parameter of the deriving class type.

This is of limited use, and it is very confusing to read, so I agree with Eric Lippert when he says you should avoid such code!

using System;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main()
        {
            var test1 = new Derived1();
            var test2 = new Derived2();

            test1.DoSomethingWithTheSameTypeAsMe(test1);
            test2.DoSomethingWithTheSameTypeAsMe(test2);
        }
    }

    public class Entity
    {
        public string Hello()
        {
            return "Hello, World.";
        }
    }

    public abstract class Entity<T>: Entity where T: Entity<T>
    {
        public abstract void DoSomethingWithTheSameTypeAsMe(T item);
    }

    public sealed class Derived1: Entity<Derived1>
    {
        // You are forced to implement DoSomethingWithTheSameTypeAsMe() with a param type "Derived1".
        // (i.e. the parameter is the same type as 'this')

        public override void DoSomethingWithTheSameTypeAsMe(Derived1 item)
        {
            Console.WriteLine("Doing something with a Derived1 item: " + item.Hello());
        }
    }

    public sealed class Derived2: Entity<Derived2>
    {
        public override void DoSomethingWithTheSameTypeAsMe(Derived2 item)
        {
            Console.WriteLine("Doing something with a Derived2 item: " + item.Hello());
        }
    }
}
Related Question