Создание во время выполнения выражения LINQ
Скажи, у меня есть это выражение:
int setsize = 20;
Expression predicate = x => x.Seed % setsize == 1
|| x.Seed % setsize == 4;
Это в основном вышлоперегородки набор элементов на 20 разделов и извлекает из каждого набора каждый первый и четвертый элемент.
Это выражение передаетсяMongoDB что этоВодитель прекрасно умеет переводить на MongoDB "запрос», Однако предикат также можно использовать в списке объектов (LINQ2Objects) и т. Д. Я хочу, чтобы это выражение можно было использовать повторно (DRY). Тем не менее, я хочу быть в состоянии пройти вIEnumerable
указать, какие элементы получить (так что 1 и 4 не "жёстко» внутрь):
public Expression GetPredicate(IEnumerable items) {
//Build expression here and return it
}
СLINQPad используя этот код:
int setsize = 20;
Expression 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]
или же[8]
или же[1, 2, 3, 4, 5, 6, ..., 16]
).
Я пытался использоватьBinaryExpressions и т. д. но ещеЯ не смог правильно построить это сообщение. Основная проблема заключается в том, что большинство моихпопыткаСбой при передаче предиката в MongoDB."жёстко» версия работает отлично но почему-то все мои попытки передать мои динамические выражения не могут быть преобразованы в запрос MongoDB драйвером C #:
{
"$or" : [{
"Seed" : { "$mod" : [20, 1] }
}, {
"Seed" : { "$mod" : [20, 4] }
}]
}
По сути, я хочу динамически построить выражение во время выполнения таким образом, чтобы оно точно копировало то, что генерирует компилятор для 'жёстко» версия.
Любая помощь будет оценена.
РЕДАКТИРОВАТЬ
Как и просили в комментариях (а такжеразмещено на pastebin), одна из моих попыток ниже. Я'Если вы разместите его в вопросе для справки о будущем, то должен его снять или прекратить их обслуживание или ...
using MongoRepository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
class Program
{
static void Main(string[] args)
{
MongoRepository repo = new MongoRepository();
var reporesult = repo.All().Where(IsInSet(new[] { 1, 4 }, 20)).ToArray();
}
private static Expression IsInSet(IEnumerable seeds, int setsize)
{
if (seeds == null)
throw new ArgumentNullException("s");
if (!seeds.Any())
throw new ArgumentException("No sets specified");
return seeds.Select(seed => x => x.Seed % setsize == seed).JoinByOr();
}
}
public class Foo : Entity
{
public int Seed { get; set; }
}
public static class Extensions
{
public static Expression JoinByOr(this IEnumerable 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(body, param);
}
}
Это приводит к:Unsupported where clause: