#c# #linq #lambda #expression #iqueryable
#c# #linq #лямбда — выражение #выражение #iqueryable #лямбда
Вопрос:
Предположим, у меня есть следующие объекты:
public class Source { public string Name; }
public class Target { public string Name; }
public class Result
{
public Source SourceObj;
public Target TargetObj;
}
Теперь, получив IQueryable<Result>
откуда-то, я хотел бы подготовить для него фильтр выражений, просто имея целевой фильтр в качестве выражения: Expression<Func<Target, bool>> filter
. Сигнатура метода фильтра выглядит следующим образом:
public Expression<Func<Result, bool>> Filter(IQueryable<Result> collection, Expression<Func<Target, bool>> targetFilter)
{
in result expression: "in given collection select items where their property TargetObj satisfies targetFilter"
}
Любые предложения будут очень оценены. Спасибо
Комментарии:
1. В чем здесь вопрос?
Ответ №1:
Я не совсем уверен, что правильно понял вашу цель, но вот то, что я думаю, вероятно, то, что вы хотите.
С помощью linq Select
вы можете сопоставить элемент из вашей исходной коллекции. Итак, здесь мы сопоставляем результат с целью, а затем применяем ваш целевой фильтр.
public IQueryable<Target> GetFilteredTargets(IQueryable<Result> collection, Expression<Func<Target, bool>> targetFilter)
{
return collection.Select(result => result.Target).Where(targetFilter);
}
Ответ №2:
Если вам действительно нужно выражение в качестве возврата для вашего Filter
метода, вам не нужно IQueryable<Result> collection
.
public Expression<Func<Result, bool>> Filter(Expression<Func<Target, bool>> targetFilter)
{
Func<Target, bool> func = targetFilter.Compile();
Expression<Func<Result, bool>> resultExpression = r => func(r.TargetObj);
return resultExpression;
}
использование:
var results = new List<Result>()
{
new Result() { TargetObj = new Target() { Name = "A" }},
new Result() { TargetObj = new Target() { Name = "B" }},
new Result() { TargetObj = new Target() { Name = "C" }},
};
var expression = Filter(r => r.Name == "B");
var func = expression.Compile();
var filteredResults = results.Where(r => func(r));
Образец отфильтрованного результата здесь вернет цель с помощью B. Для меня было бы разумнее использовать Linq, где напрямую основано на моем понимании вашей цели.
РЕДАКТИРОВАТЬ: поскольку вы добавили новый фактор в свой вопрос, вот как вы можете добавить целевой фильтр к базовому фильтру.
public Expression<Func<Result, bool>> Filter(Expression<Func<Result, bool>> baseFilter, Expression<Func<Target, bool>> targetFilter)
{
Func<Result, bool> baseFunc = baseFilter.Compile();
Func<Target, bool> targetFunc = targetFilter.Compile();
Expression<Func<Result, bool>> resultExpression = r => baseFunc(r) amp;amp; targetFunc(r.TargetObj);
return resultExpression;
}
Комментарии:
1. Чтобы быть более понятным, я просто хочу немного исправить свой вопрос. Предположим, я создаю сложное выражение фильтра для запроса результатов. Вместо
IQueryable<Result> collection
моего метода Filter должен иметь параметр baseFilter и выглядетьpublic Expression<Func<Result, bool>> Filter(Expression<Func<Result, bool>> baseFilter, Expression<Func<Target, bool>> targetFilter)
следующим образом. Цель этого метода — каким-то образом «объединить» эти два фильтра, сделав targetFilter «внутренним» фильтром базового фильтра. Спасибо2. @TimurGinesin Я обновил свой ответ, чтобы показать, как вы можете комбинировать свои базовые и целевые выражения фильтра.