Fan
Fan

Reputation: 315

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?

Upvotes: 6

Views: 151

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1502835

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.

Upvotes: 4

Related Questions