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?
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With