Casting to a curiously recurring derived class

Viewed 93

I have a code base using the curiously recurring template pattern, with a base and a derived class.
In a certain method that accepts a base class parameter, I would like to check if the parameter I received is of a derived type, but I cannot cast to it.
Here's an example that illustrates the problem:

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

class Derived<T> : Base<T>
    where T : Derived<T> { 
}

class DerivedBanana : Derived<DerivedBanana> { 
}

class Program {

    static void DoSomething<T>(T t) where T : Base<T> {
        // CS0311: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Derived<T>'.
        // There is no implicit reference conversion from 'T' to 'Derived<T>'.
        var d = t as Derived<T>;
    }

    static void Main(string[] args) {
        DoSomething(new DerivedBanana());
    }
}

Is there a way I can check in my DoSomething method if the T parameter I'm getting is actually a Derived<T>?

Note: I'm refactoring my code to avoid this situation, but I would still like to know how to do such a cast :)

Note 2: The suggested duplicate does not answer my question: I want to know how to cast to the derived type, not just check if the variable is of the derived type.

1 Answers

Is there a way I can check in my DoSomething method if the T parameter I'm getting is actually a Derived?

The Derived<T> class could be constrained with Base<T> getting a little weaker form of type safety

public class Base<T> where T : Base<T>
{
    public virtual Base<T> This(){
        return this as T;
    }
}

public class Derived<T> : Base<T>
    where T: Base<T>
{
    public override Derived<T> This()
    {
        return base.This() as Derived<T>;
    }
}

class DerivedBanana : Derived<DerivedBanana>
{
}

class BaseBanana : Base<BaseBanana>
{
}


class Program
{

    static void DoSomething<T>(T t) where T : Base<T>
    {
        
        T d = (T)(t.This() as Derived<T> ?? t.This() as Base<T>); 
        Console.WriteLine(d.GetType());
    }

    static void Main(string[] args)
    {   
        DoSomething(new BaseBanana());
        DoSomething(new DerivedBanana());
    }
}
Related