表达式树:未为类型定义的二元运算符
Expression Trees: Binary operator not defined for types
我正在使用 ExpressionVisitor class 动态更改发送到数据库的搜索查询。我想用 Contains 方法替换二进制 Or 表达式,它是 AndAlso 表达式的左操作数,但我目前的代码生成以下错误:
The binary operator AndAlso is not defined for the types
'System.Func`2[foo.MV,System.Boolean]' and 'System.Boolean'.
Expression AndAlso 文档建议我应该能够提供 (Expression, Expression) 作为此 Binary AndAlso Expression 的参数,但下面的代码显然不满足左操作数的要求:
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);
}
}
我了解基本信息:类型不匹配,但我看不出我还需要做些什么才能将我的替换代码转换为有效的东西,而且我查看过的所有示例代码都有场景太简单了。
更新:
感谢安东尼。关键字:"Outside the 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
重新创建的。当你向下看而不是向上看时会容易得多;)
你应该直接 return containsExp
,传递 Expression.Lambda
作为 And
的参数是没有意义的。 And
可以对布尔值进行操作。如果结果是布尔值,它可以对函数的结果进行操作。但它不能将函数本身作为参数。
你所做的基本上就是
bool res = ((Func<MV, bool>)(mv => FtsIds.Contains(mv.MVID))) && true;
我正在使用 ExpressionVisitor class 动态更改发送到数据库的搜索查询。我想用 Contains 方法替换二进制 Or 表达式,它是 AndAlso 表达式的左操作数,但我目前的代码生成以下错误:
The binary operator AndAlso is not defined for the types 'System.Func`2[foo.MV,System.Boolean]' and 'System.Boolean'.
Expression AndAlso 文档建议我应该能够提供 (Expression, Expression) 作为此 Binary AndAlso Expression 的参数,但下面的代码显然不满足左操作数的要求:
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);
}
}
我了解基本信息:类型不匹配,但我看不出我还需要做些什么才能将我的替换代码转换为有效的东西,而且我查看过的所有示例代码都有场景太简单了。
更新:
感谢安东尼。关键字:"Outside the 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
重新创建的。当你向下看而不是向上看时会容易得多;)
你应该直接 return containsExp
,传递 Expression.Lambda
作为 And
的参数是没有意义的。 And
可以对布尔值进行操作。如果结果是布尔值,它可以对函数的结果进行操作。但它不能将函数本身作为参数。
你所做的基本上就是
bool res = ((Func<MV, bool>)(mv => FtsIds.Contains(mv.MVID))) && true;