假设我有这个 lambda 表达式,我想在上面写一个表达式树:
query.Where(d => (allCk && d.FacilityId == facilityId) //1.
||
(!allCk && allSelected && d.FacilityId == facilityId && !ids.Contains(d.Id)) //2.
||
(!allCk && !allSelected && ids.Contains(d.Id))) //3.
这就是我设法编写它的方式:为简洁起见,我将只显示第二个条件,它是最复杂的(!allCk && allSelected && d.FacilityId == facilityId && !ids.Contains(d.Id))
.
private Expression<Func<Documents, bool>> GetDocumentsPredicate(
int facilityId, bool allCk, bool allSelected, List<int> ids)
{
ParameterExpression pe = Expression.Parameter(typeof(Documents), "d");
var listExpr1 = new List<Expression>();
listExpr1.Add(Expression.IsFalse(Expression.Constant(allCk))); //allCk
listExpr1.Add(Expression.Constant(allSelected)); //allSelected
var facilityParam = Expression.Constant(facilityId); //facility
Expression facilityIdProp = Expression.Property(pe, "FacilityId");
Expression facilityIdEql = Expression.Equal(facilityIdProp, facilityParam);
listExpr1.Add(facilityIdEql);
//This is where I'm having trouble... Is ids a parameter or a constant???
//Assuming it's a parameter...
ParameterExpression peIds = Expression.Parameter(typeof(List<int>), "ids");
Expression listContains = Expression.Call(
pIds,
typeof(List<int>).GetMethod("Contains"),
Expression.Property(pe, "Id"));
listExpr1.Add(Expression.Call(peIds, listContains, Expression.Property(pe, "Id")));
var exp1 = listExpr1
.Skip(1)
.Aggregate(listExpr1[0], Expression.AndAlso);
//...
}
我在这一行遇到错误:listExpr1.Add(Expression.Call(pIds, listContains, Expression.Property(pe, "Id")));
// 无法将“Linq.Expression.ParameterExpression”转换为“System.Reflection.MethodInfo”。所以,它在抱怨pIds。
那么这里的 ids 是什么,是常量、参数还是其他东西?
谢谢你的帮助
这就是我写整个方法的方式
private Expression<Func<Documents, bool>> GetDocumentsPredicate(
int facilityId, bool allCk, bool allSelected, List<int> ids)
{
ParameterExpression pe = Expression.Parameter(typeof(Document), "d");
Expression constIds = Expression.Constant(ids);
Expression allCkParam = Expression.Constant(allCk);
Expression allSelectedParam = Expression.Constant(allSelected);
Expression listContains = Expression.Call(
constIds,
typeof(List<int>).GetMethod("Contains"),
Expression.Property(pe, "Id"));
/*(allCk && d.FacilityId == facilityId) ==> exp0*/
var facilityParam = Expression.Constant(facilityId);
Expression facilityIdProp = Expression.Property(pe, "FacilityId");
Expression facilityIdEql = Expression.Equal(facilityIdProp, facilityParam);
Expression exp0 = Expression.AndAlso(allCkParam, facilityIdEql);
/*(!allCk && allSelected && d.FacilityId == facilityId && !ids.Contains(d.Id)))
==> exp1 */
var listExpr1 = new List<Expression>();
listExpr1.Add(Expression.IsFalse(allCkParam));
listExpr1.Add(allSelectedParam);
listExpr1.Add(facilityIdEql);
listExpr1.Add(Expression.IsFalse(listContains));
var exp1 = listExpr1
.Skip(1)
.Aggregate(listExpr1[0], Expression.AndAlso);
/* (!allCk && !allSelected && ids.Contains(d.Id)) ==> exp2 */
var listExpr2 = new List<Expression>();
listExpr2.Add(Expression.IsFalse(allCkParam));
listExpr2.Add(Expression.IsFalse(allSelectedParam));
listExpr1.Add(listContains);
var exp2 = listExpr2
.Skip(1)
.Aggregate(listExpr2[0], Expression.AndAlso);
var listExpr = new List<Expression> { exp0, exp1, exp2 };
var exp = listExpr
.Skip(1)
.Aggregate(listExpr[0], Expression.OrElse);
var expr =
Expression.Lambda<Func<Document, bool>>(exp,
new ParameterExpression[] { pe });
return expr;
}
这是我将鼠标悬停在返回值上时得到的结果
d => (((False AndAlso (d.FacilityId == 1))
OrElse
(((IsFalse(False) AndAlso False) AndAlso (d.FacilityId == 1))
AndAlso
IsFalse(value(System.Collections.Generic.List`1[System.Int32]).Contains(d.Id))))
OrElse
((IsFalse(False) AndAlso IsFalse(False))
AndAlso
value(System.Collections.Generic.List`1[System.Int32]).Contains(d.Id)))
使用此语句进行的简单测试var count = query.Count();
会产生异常:Unknown LINQ expression of type 'IsFalse'
.
ids
就表达式树而言,它不是参数,因为它没有传递给Func<...>
. id
您需要匹配的s列表内置于表达式的结构中,因此Expression.Constant
是处理它的正确方法。
然而,这还不是全部:因为ids
是一个引用类型,所以只有对它的引用才会进入表达式的结构。因此,如果您在构造表达式后决定更改列表的内容,则 的含义ids.Contains
将发生变化。
如果这不是您想要达到的效果,请复制该列表:
Expression constIds = Expression.Constant(ids.ToList());
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句