假设我有这样的表达:
int setsize = 20;
Expression<Func<Foo, bool>> predicate = x => x.Seed % setsize == 1
|| x.Seed % setsize == 4;
这基本上将一组元素“分区”为 20 个分区,并从每个组中检索第一个和第四个元素。
该表达式被传递到MongoDB http://www.mongodb.org/这是哪个driver https://www.nuget.org/packages/mongocsharpdriver/完全能够转换为 MongoDB“查询”。但是,谓词也可以用在对象列表(LINQ2Objects)等上。我希望这个表达式可以重用(DRY http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)。但是,我希望能够通过IEnumerable<int> http://msdn.microsoft.com/en-us/library/9eekhta0.aspx指定要检索的项目(因此 1 和 4 不会“硬编码”到其中):
public Expression<Func<Foo, bool>> GetPredicate(IEnumerable<int> items) {
//Build expression here and return it
}
With LINQPad http://www.linqpad.net/使用此代码:
int setsize = 20;
Expression<Func<Foo, bool>> predicate = x => x.Seed % setsize == 1 || x.Seed % setsize == 4;
predicate.Dump();
}
class Foo
{
public int Seed { get; set; }
我可以检查这个表达式:
现在,我希望能够构建该表达式的精确再现,但要传递可变数量的整数(因此我可以传递而不是 1 和 4,例如,[1, 5, 9, 11]
or [8]
or [1, 2, 3, 4, 5, 6, ..., 16]
).
我尝试过使用二元表达式 http://msdn.microsoft.com/en-us/library/system.linq.expressions.binaryexpression.aspx等等,但无法正确构造此消息。主要问题是我的大部分attempt http://pastebin.com/qDwXGGit将谓词传递给 MongoDB 时,s 将失败。“硬编码”版本工作正常但不知怎的,我所有传递动态表达式的尝试都未能被 C# 驱动程序转换为 MongoDB 查询:
{
"$or" : [{
"Seed" : { "$mod" : [20, 1] }
}, {
"Seed" : { "$mod" : [20, 4] }
}]
}
基本上,我想在运行时动态构建表达式,使其精确复制编译器为“硬编码”版本生成的内容。
任何帮助将不胜感激。
EDIT
按照评论中的要求 https://stackoverflow.com/questions/16583565/runtime-creation-of-linq-expression#comment23832188_16583565 (and 发布到 帕斯特宾 http://pastebin.com/qDwXGGit),下面是我的尝试之一。我将其发布在问题中以供将来参考,pastebin 是否应该将其删除或停止他们的服务或...
using MongoRepository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
class Program
{
static void Main(string[] args)
{
MongoRepository<Foo> repo = new MongoRepository<Foo>();
var reporesult = repo.All().Where(IsInSet(new[] { 1, 4 }, 20)).ToArray();
}
private static Expression<Func<Foo, bool>> IsInSet(IEnumerable<int> seeds, int setsize)
{
if (seeds == null)
throw new ArgumentNullException("s");
if (!seeds.Any())
throw new ArgumentException("No sets specified");
return seeds.Select<int, Expression<Func<Foo, bool>>>(seed => x => x.Seed % setsize == seed).JoinByOr();
}
}
public class Foo : Entity
{
public int Seed { get; set; }
}
public static class Extensions
{
public static Expression<Func<T, bool>> JoinByOr<T>(this IEnumerable<Expression<Func<T, bool>>> filters)
{
var firstFilter = filters.First();
var body = firstFilter.Body;
var param = firstFilter.Parameters.ToArray();
foreach (var nextFilter in filters.Skip(1))
{
var nextBody = Expression.Invoke(nextFilter, param);
body = Expression.Or(body, nextBody);
}
return Expression.Lambda<Func<T, bool>>(body, param);
}
}
这导致:Unsupported where clause: <InvocationExpression>
.