Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 661
Fan Avatar asked May 12 '14 22:05

Fan


People also ask

Can a generic class have multiple constraints?

There can be more than one constraint associated with a type parameter. When this is the case, use a comma-separated list of constraints. In this list, the first constraint must be class or struct or the base class.

What is generic type constraint?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.

What is the purpose of an interface constraints on a type parameter?

Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.


1 Answers

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.

like image 66
Jon Skeet Avatar answered Nov 14 '22 18:11

Jon Skeet