表达式树:未为类型

时间:2018-04-15 00:44:03

标签: c# linq expression-trees

我正在使用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重新创建的。当你俯视而不是向上时,这样容易得多;)

1 个答案:

答案 0 :(得分:2)

您应该直接返回containsExp,将Expression.Lambda作为And的参数传递是没有意义的。 And可以对布尔值进行操作。如果结果是布尔值,它可以对函数结果进行操作。但它不能把功能本身作为一种论据。

你所做的基本上是

bool res = ((Func<MV, bool>)(mv => FtsIds.Contains(mv.MVID))) && true;