You probably already know this, but just for the sake of completeness:
You can't use re-linq to query from a List<Person> because re-linq is
based on IQueryable<T> and List<T> does not implement IQueryable<T>.
You usually need a class derived from re-linq's QueryableBase<T> as an
entry point for re-linq-based queries.
That aside, to your question. If I understand correctly, you want to
know how to handle the projection when you've already figured out how
to execute the rest of the query (from clauses, where clauses, order
by clauses, etc.) against your query source, right?
The answer is: unless your target query system allows you to specify
such complex projections (and most don't), you'll have to simulate
them in memory. To do so, I'd suggest the following steps:
First, wrap the items coming from your target query system into some
result object; I'll call it ResultItem. ResultItem must provide a
method to access queried objects via the respective IQuerySources the
object originates from:
public class ResultItem
{
private readonly Dictionary<IQuerySource, object>
_resultObjectsBySource = new Dictionary<IQuerySource, object> ();
public void Add (IQuerySource querySource, object resultObject)
{
_resultObjectsBySource.Add (querySource, resultObject);
}
public T GetObject<T> (IQuerySource source)
{
return (T) _resultObjectsBySource[source];
}
}
Then, implement an expression tree visitor that builds an in-memory
projector for the select expression of your QueryModel. An in-memory
projector is a delegate with a signature of "Func<ResultItem, T>"
(where T is the projection's result type) that executes the projection
against a ResultItem. To build it, define a parameter expression for
the ResultItem, then simply replace every
QuerySourceReferenceExpression in the select expression with an
expression that gets the referenced object from that parameter:
protected override Expression VisitQuerySourceReferenceExpression
(QuerySourceReferenceExpression expression)
{
var getObjectGenericMethodDefinition = typeof (ResultItem).GetMethod
("GetObject")
var getObjectMethod =
getObjectGenericMethodDefinition.MakeGenericMethod (expression.Type);
return Expression.Call (_resultItemParameter, getObjectMethod,
Expression.Constant (expression.ReferencedQuerySource));
}
Take the transformed select expression and the ResultItem parameter
and compile them into a delegate; this is your in-memory projector.
You can now apply that projector to the result items stemming from
your query to the target system.
In case that's too abstract, I've put together a sample implementation
(I've wanted to do that for some time anyway) here:
<https://svn.re-motion.org/svn/Remotion-Contrib/Samples/re-linq/ProjectionSupport/>.
Hope this helps,
Fabian