I came across an issue with creating a generic list of our query classes. These query classes are derived from a base abstract generic class with a self referencing type constraint.
The stripped down base class and derived classes are:
public abstract class AbstractQuery<TQuery, TResult>
where TQuery : AbstractQuery<TQuery, TResult>
{
public IEnumerable<TResult> Query ()
{
return new List<TResult>();
}
}
public class FirstQuery : AbstractQuery<FirstQuery, object> { }
public class SecondQuery : AbstractQuery<SecondQuery, object> { }
The application code wants to create a list of these queries and execute the Query method on each, such as:
var queryList = new List<AbstractQuery<AbstractQuery, object>>
{
new FirstQuery(),
new SecondQuery()
};
foreach ( var query in queryList )
{
query.Query();
}
This part does not build because the List type is invalid of course. So my question is what type can I use for the List to have this code function correctly?
As a side note, we did solve this another way by adding an IQuery interface with a Query method signature that AbstractQuery implements, but still wanted to see if the initial way was possible. And yes, there is a reason for the self referencing constraint in the actual code - its needed for some reflection code.
You're trying to treat AbstractQuery<TQuery, TResult> as being covariant with respect to TQuery. Classes cannot be covariant with respect to generic arguments. Only interfaces (and even then, only under certain circumstances) are allowed to make their generic arguments variant (either covariant or contravariant). That's why it can work if you use an interface instead of an abstract class.
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