我正在使用ExpressionVisitor类来动态更改发送到数据库的搜索查询。我想用Contains方法替换二进制Or表达式,它是AndAlso表达式的左操作数,但我现在的代码生成以下错误:
没有为类型定义二元运算符AndAlso 'System.Func`2 [foo.MV,System.Boolean]'和'System.Boolean'。
Expression AndAlso文档表明我应该能够提供(表达式,表达式)作为此二进制AndAlso表达式的参数,但下面的代码显然不满足左操作数的要求:
protected override Expression VisitBinary(BinaryExpression b) {
if (b.NodeType == ExpressionType.Or) {
ParameterExpression vParam = Expression.Parameter(typeof(MV), "mv");
var mvID = Expression.Property(vParam, "MVID");
ConstantExpression ftsIDs = Expression.Constant(FtsIds, typeof(List<long>));
var containsInfo = typeof(List<long>).GetMethod("Contains", new Type[] { typeof(long) });
var containsExp = Expression.Call(ftsIDs, containsInfo, new Expression[] { mvID });
return Expression.Lambda<Func<MV, bool>>(containsExp, vParam);
}
}
我理解基本信息:类型不匹配但是我看不出还有什么需要做的才能将我的替换代码转换为有效的东西,而我所看到的所有示例代码都有以下情况太简单了。
更新
感谢Antonin。关键词:“在epxression之外”。 vParam已经定义。
上面的代码正在重新创建它,编译器可能会给它一个时髦的名字......最终是一个引用不同的实例。实际需要做的是收集现有的vParam表达式,如下所示:
protected override Expression VisitBinary(BinaryExpression b) {
if (b.NodeType == ExpressionType.Or) {
MethodCallExpression mce = this.Visit(b.Left) as MethodCallExpression;
MemberExpression mex = mce?.Object as MemberExpression;
var mvID = Expression.Property(mex.Expression, "MVID"); // << Injecting existing param here
ConstantExpression ftsIDs = Expression.Constant(FtsIds, typeof(List<long>));
var containsInfo = typeof(List<long>).GetMethod("Contains", new Type[] { typeof(long) });
var containsExp = Expression.Call(ftsIDs, containsInfo, new Expression[] { mvID });
return containsExp;
}
}
由于mex.Expression
包含对原始ParameterExpression
的引用,原始代码实际上是通过vParam
重新创建的。当你俯视而不是向上时,这样容易得多;)
答案 0 :(得分:2)
您应该直接返回containsExp
,将Expression.Lambda
作为And
的参数传递是没有意义的。 And
可以对布尔值进行操作。如果结果是布尔值,它可以对函数结果进行操作。但它不能把功能本身作为一种论据。
你所做的基本上是
bool res = ((Func<MV, bool>)(mv => FtsIds.Contains(mv.MVID))) && true;