Search code examples
c#genericstype-constraints

Priorities of multiple constraints on a generic type parameter


In the following example, I have two constraints, Foobar and IFoobar<T>, on type T in generic class FoobarList<T>. But the compiler gives an error: Cannot implicitly convert type 'Foobar' to 'T'. An explicit conversion exists (are you missing a cast?)

interface IFoobar<T>
{
    T CreateFoobar();
}

class Foobar : IFoobar<Foobar>
{
    //some foobar stuffs
    public Foobar CreateFoobar() { return new Foobar(); }
}

class FoobarList<T> where T : Foobar, IFoobar<T>
{
    void Test(T rFoobar)
    {
        T foobar = rFoobar.CreateFoobar(); //error: cannot convert Foobar to T
    }
}

It seems the compiler considers CreateFoobar as a method in Foobar, but not the one in IFoobar. I can fix the compile by dividing Foobar into a base class FoobarBase, and implementing the interface IFoobar in its derived class, as follows:

interface IFoobar<T>
{
    T CreateFoobar();
}

abstract class FoobarBase
{
    //some foobar stuffs
}

class Foobar : FoobarBase, IFoobar<Foobar>
{
    public Foobar CreateFoobar() { return new Foobar(); }
}

class FoobarList<T> where T : FoobarBase, IFoobar<T>
{
    void Test(T rFoobar)
    {
        T foobar = rFoobar.CreateFoobar();
    }
}

It is cumbersome to divide Foobar into two classes. Is there a better way to fix this?


Solution

  • Just cast rFoobar to IFoobar<T>:

    T foobar = ((IFoobar<T>)rFoobar).CreateFoobar();
    

    That way you're calling a method that returns T rather than just Foobar.

    As Rotem suggests, changing the method in Foobar to use explicit interface implementation works too:

    Foobar IFoobar<Foobar>.CreateFoobar() { return new Foobar(); }
    

    That way that method won't be found in T, so again it will resolve to the interface method.