BCqrstoO BCqrstoO - 3 months ago 26
C# Question

C# Generic Extension Method Boxing Conversion Issue

I'm working on migrating/rewriting some Java generics in C#. I'm getting an error that I don't understand.

(This is partially an experiment based on composition over inheritance to limit bloat for child-classes that don't need some functionality, but it's also just an experiment to better understand C# generics.)

Note: the actual child-class implementations actually work like I expect, it's just the extension method that isn't compiling.

A parent class:

public abstract class PageObject<T> where T : PageObject<T>
{

protected IWebDriver WebDriver => ServiceLocator.GetWebDriver();

public PageObject()
{
PageFactory.InitElements(WebDriver, this);
}

// ... more stuff, but the constructor is the important thing that keeps
// me using an abstract parent class. There are some abstract methods
// that return T so the child classes can return "this" in a fluent api.
}


An interface:

public interface IHasCustomLoadCondition<T> where T : PageObject<T>
{
bool IsLoaded();
}


and an extension method, this is where the error is occuring:

public static T WaitForCustomPageLoad<T>(this T page) where T : IHasCustomLoadCondition<T>
{
wait.Until<bool>((d) =>
{
return page.IsLoaded();
});
return page;
}


The error message:

The type 'T' cannot be used as type parameter 'T' in the generic type or method
'IHasCustomLoadCondition<T>'. There is no boxing conversion or type parameter conversion
from 'T' to 'PageObject<T>'.

Answer

Since you have this declaration:

public interface IHasCustomLoadCondition<T> where T : PageObject<T>
                                            ^---------------------^

You must ensure you also carry this constraint into derived interfaces, implementing classes and methods that are also generic on the same T, so this method:

public static T WaitForCustomPageLoad<T>(this T page) where T : IHasCustomLoadCondition<T>

Must also have this constraint:

public static T WaitForCustomPageLoad<T>(this T page)
    where T : PageObject<T>, IHasCustomLoadCondition<T>

Basically:

public static T WaitForCustomPageLoad<T>(this T page) where T : IHasCustomLoadCondition<T>
                                      ^                                                 ^
                                      |                                                 |
                                      +-------- constraints must be compatible ---------+