I have a program that passes some query criteria, for multiple types of class, that is used by EF to query data back from a db. There is a criteria class for each type that is being queried, but there is a lot of duplication and similarity between these methods which I'd hoped to refactor out, but without success.
These are example (simplified) service methods:
private static IQueryable<Class1> FilterClass1ResultsOnId(Class1QueryCriteria queryCriteria, IQueryable<Class1> queryResults)
{
if (!string.IsNullOrEmpty(queryCriteria.Id))
{
queryResults = from view in queryResults where view.Id==queryCriteria.Id select view;
}
return queryResults;
}
private static IQueryable<Class2> FilterClass2ResultsOnId(Class2QueryCriteria queryCriteria, IQueryable<Class2> queryResults)
{
if (!string.IsNullOrEmpty(queryCriteria.Id))
{
queryResults = from view in queryResults where view.Id == queryCriteria.Id select view;
}
return queryResults;
}
... which are called like this ...
queryResults = FilterClass1ResultsOnId(queryCriteria, queryResults);
The service has a series of these 'FilterClassXonSOMECRITERIA' methods to narrow down the IQueryable that is ultimately returned. There are a lot of these service methods that are essentially identical apart from the type of the input parameters and the type of the output.
I initially tried to refactor the methods to accept a queryResults
argument that was an interface rather than a concrete class - a simple interface that just has an Id
property - and then made Class1
and Class2
implement that interface. But then I need to make the return type of these methods non-concrete too if I want to use just the one method. This is where I got stuck.
I have been looking around and have seen covariance and contravariance information, but I can't seem to define a method/interface that uses these interfaces and a generic type without getting 'cannot resolve symbol T' or 'Argument type XXX is not assignable to parameter type YYY''.
At this point I wanted to sanity check with those more familiar with this problem: Is what I am trying to do possible? Can I have methods that take an argument specified only by interface, and return from that method an object also only specified by an interface?
EDIT: the criteria classes are pretty straightforward, and are actually complex types defined in the EF model. But here's a simplified example:
public class Class1QueryCriteria
{
public string Id;
public string Name;
}
public class Class2QueryCriteria
{
public string Id;
public string Category;
}