Reputation: 12142
How can the following simple lambda be represented using Expression Tree syntax?
v.Tags.Any(t => searchTags.Contains(t.ID));
Where :
Variations on the following have been tried:
var anyInfo = typeof(Queryable).GetMethods()
.Where(m => m.Name == "Any")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(Tag));
var toQueryable = typeof(Queryable).GetMethods()
.Where(m => m.Name == "AsQueryable")
.Single(m => m.IsGenericMethod)
.MakeGenericMethod(typeof(Tag));
var containsInfo = typeof(List<long>).GetMethod("Contains", new Type[] { typeof(long) });
var list = Expression.Constant(searchTags);
var mcvalue = Expression.Property(v, "Tags");
ParameterExpression tagParam = Expression.Parameter(typeof(Tag), "mt");
var tagID = Expression.Property(tagParam, "ID");
var st = Expression.Call(list, containsInfo, tagID);
return Expression.Call(null, anyInfo, Expression.Call(null, toQueryable, mcvalue), st);
Upvotes: 1
Views: 462
Reputation: 205649
Here is the C# equivalent of the result of your return
statement:
v.Tags.AsQueryable().Any(searchTags.Contains(t.ID))
Aside from the redundant AsQueryable()
call, the main issue is that neither the result, nor the Any
call argument are lambda expressions, but expressions representing a potential lambda expression body. In order to convert them to lambda expressions (and connect with the associated parameter expressions), you need to use one of the Expression.Lambda
method overloads.
So building lambda expression like
v => v.Tags.Any(t => searchTags.Contains(t.ID));
could be done with something like this:
static Expression<Func<T, bool>> SampleLambda<T>(List<long> searchTags)
{
var v = Expression.Parameter(typeof(T), "v");
var t = Expression.Parameter(typeof(Tag), "t");
var containsCall = Expression.Call(
typeof(Enumerable), "Contains", new [] { typeof(long) },
Expression.Constant(searchTags),
Expression.Property(t, "ID")
);
var anyCall = Expression.Call(
typeof(Enumerable), "Any", new [] { typeof(Tag) },
Expression.Property(v, "Tags"),
Expression.Lambda(containsCall, t)
);
return Expression.Lambda<Func<T, bool>>(anyCall, v);
}
Upvotes: 2