是否可以通过快捷方式将此代码
Expression<Func<MyType, bool>> a => t => ...;
Expression<Func<MyType, bool>> b => t => ...;
Expression<Func<MyType, bool>> c => t => ...;
await myIQueryableOfMyType
.Where(a)
.Where(b)
.Where(c)
.ToArrayAsync()
在某种程度上,我有一个带有Exphere子句的Experssion。 我的目的是将“ a”,“ b”,“ c”表达式替换为可变条件集。
我试图聚合一个函数并将其设置在新的Lambda表达式中
Expression<Func<MyType, bool>>[] predicates = ...
Func<MyType, bool> func = t => predicates == null || predicates.Aggregate(true, (prev, current) => prev && current.Compile()(t));
但不适用于实体框架的IQueryable集合
答案 0 :(得分:2)
表达基本上是内存中的代码表示形式,因此绝对有可能。
示例代码:
static void Main(string[] args)
{
Expression<Func<MyType, bool>> a = t => t.Id == 1;
Expression<Func<MyType, bool>> b = t => t.Name == "Name1";
Expression<Func<MyType, bool>> c = t => t.Desc == "Desc1";
Expression<Func<MyType, bool>> combined = LinqExtensions.And(a, b, c);
await myIQueryableOfMyType
.Where(combined)
.ToArrayAsync()
}
public static class LinqExtensions
{
// Combine array of predicates into one
// For example for input:
// [ t1 => t1.Id == 1, t2 => t2.Name == "Name1", t3 => t3.Desc == "Desc1" ]
// output will be
// p => p.Id == 1 && p.Name == "Name1" && p.Desc == "Desc1"
public static Expression<Func<T, bool>> And<T>(params Expression<Func<T, bool>>[] predicates)
{
// this is `p`
ParameterExpression param = Expression.Parameter(typeof(T));
Expression body = null;
foreach (Expression<Func<T, bool>> predicate in predicates)
{
body = body == null
// first expression, just assign it to body
? predicate.Body
// join body with predicate using &&
: Expression.AndAlso(body, predicate.Body);
}
// Create lambda
return Expression.Lambda<Func<T, bool>>(
// this is where we replace t1, t2, t3 with p
new ParamExpressionVisitor(param).Visit(body),
param
);
}
private class ParamExpressionVisitor : ExpressionVisitor
{
private ParameterExpression _parameter;
public ParamExpressionVisitor(ParameterExpression parameter)
{
this._parameter = parameter;
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == this._parameter.Type)
{
return this._parameter;
}
return base.VisitParameter(node);
}
}
}