I have a Linq query with a select
, from my Linq query provider it I get an expression tree containing a MethodCallExpression
, but just how can I get the select projections from the MethodCallExpression
?
internal static object Execute(Expression expression, bool isEnumerable)
{
var whereExpression = expression as MethodCallExpression;
if (whereExpression == null) throw new InvalidProgramException("Error");
foreach (var arg in whereExpression.Arguments)
{
if (arg is UnaryExpression)
{
var unaryExpression = arg as UnaryExpression;
var lambdaExpression = unaryExpression.Operand as LambdaExpression;
if (lambdaExpression == null) continue;
// Here I would like to get the select projections, in this example the "word" projection ...
Query may look like:
var queryable = new MyQueriableClass();
var query = from thing in queryable
where thing.id == 1
select word;
It isn't exactly clear what you are doing, but
// note the AsQueryable! Otherwise there is no
// Expression tree!
var words = new List<string>() { "an", "apple", "a", "day" }.AsQueryable();
// Note that even IQueryable<string> query = words;
// is a perfectly good query without a projection!
// The query
// from word in words where word.Length > 0 select word
// doesn't have a select too (try looking at the
// expression tree... The select has been elided)
// The projection if not present is implicit, the
// whole object.
var query = from word in words
select word;
var exp = query.Expression;
var methodCallExpression = exp as MethodCallExpression;
if (methodCallExpression != null)
{
MethodInfo method = methodCallExpression.Method;
if (method.DeclaringType == typeof(Queryable) && method.Name == "Select")
{
var source = methodCallExpression.Arguments[0];
var selector = methodCallExpression.Arguments[1];
// The selector parameter passed to Select is an
// Expression.Quote(subexpression),
// where subexpression is the lambda expression
// word => word here
if (selector.NodeType != ExpressionType.Quote)
{
throw new NotSupportedException();
}
UnaryExpression unary = (UnaryExpression)selector;
Expression operand = unary.Operand;
if (operand.NodeType != ExpressionType.Lambda)
{
throw new NotSupportedException();
}
LambdaExpression lambda = (LambdaExpression)operand;
// This is the "thing" that returns the result
Expression body = lambda.Body;
}
}
The body
at the end should be what you want (or perhaps the lambda
just before the end). Note the comments at the beginning of the code block.