异常使用OrElse和AndAlso表达式方法 [英] Exception using OrElse and AndAlso expression methods

查看:132
本文介绍了异常使用OrElse和AndAlso表达式方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我在我的输入中有一个条件类列表,它们具有以下形式:

  public class Filter 
{
public string field {get;组; }
public string operator {get;组; }
public string value {get;组;
}

当我构建表达式对象我以下列方式为每个条件创建一个表达式

  foreach(规则中的filter sf){
表达式ex = sf.ToExpression(query);
if(mainExpression == null){
mainExpression = ex;
}
else {
if(logicalCondition ==AND){
mainExpression = Expression.And(mainExpression,ex);
}
else if(logicalCondition ==OR){
mainExpression = Expression.Or(mainExpression,ex);
}
}
}

Filter.ToExpression()方法是这样执行的

  public override表达式ToExpression(IQueryable query){
ParameterExpression parameter = Expression.Parameter(query .ElementType,p);
MemberExpression memberAccess = null;
foreach(field.Split('。')中的var属性)
memberAccess = MemberExpression.Property(memberAccess ??(参数为Expression),属性);
ConstantExpression filter = Expression.Constant(Convert.ChangeType(value,memberAccess.Type));
WhereOperation condition =(WhereOperation)StringEnum.Parse(typeof(WhereOperation),operator);
LambdaExpression lambda = BuildLambdaExpression(memberAccess,filter,parameter,condition,value);
返回lambda;
}

当我有一个单一的条件,但是当我尝试使用其中一个 AndAlso OrElse 静态方法我收到一个 InvalidOperationException 说:


二进制运算符或不是为类型
'System.Func 2 [MyObject,System.Boolean]'和
'System.Func 2 [MyObject,System.Boolean]'。


我有点困惑。有人可以更好地解释异常的原因并提出解决方案吗?



非常感谢!

解决方案

您正在组合 a => a == 3 a => a == 4 into (a => a == 3)|| (a => a == 4),但您应该试图使它 a => (a == 3 || a == 4)。这不是太难做手动,但有人已经为你做了这个。寻找组合表达式。



修改:按照要求,一个简单的例子说明如何手动执行。



编辑2 :它使用.NET $ 4中新增的 ExpressionVisitor ,但在MSDN,您可以找到早期版本的可用实现。我假设MSDN代码不符合第三方的目的。您只需将受保护的虚拟表达式访问(Expression exp)方法更改为 public 。而作为 Enumerable.Zip 是不可用的,没有必要,现在已经走了。

 使用系统; 
使用System.Collections.Generic;
使用System.Diagnostics;
使用System.Linq;
使用System.Linq.Expressions;

命名空间DemoApp
{
<包含.NET 3.5的ExpressionVisitor定义>

public class ExpressionParameterReplacer:ExpressionVisitor
{
public ExpressionParameterReplacer(IList< ParameterExpression> fromParameters,IList< ParameterExpression> toParameters)
{
ParameterReplacements = new Dictionary< ; ParameterExpression,ParameterExpression>();
for(int i = 0; i!= fromParameters.Count&&&i!= toParameters.Count; i ++)
ParameterReplacements.Add(fromParameters [i],toParameters [i]);
}
private IDictionary< ParameterExpression,ParameterExpression> ParameterReplacements
{
get;
设置;
}
protected override表达式访问参数(ParameterExpression节点)
{
ParameterExpression替换;
if(ParameterReplacements.TryGetValue(node,out replacement))
node = replacement;
return base.VisitParameter(node);
}
}

类程序
{
static void Main(string [] args)
{
表达式&FunC< ; int,bool>>> exprA = a => a == 3;
表达式< Func< int,bool>>> exprB = b => b == 4;
表达式< Func< int,bool>>> exprC =
Expression.Lambda Expression.OrElse(
exprA.Body,
new ExpressionParameterReplacer(exprB.Parameters,exprA.Parameters) .Visit(exprB.Body)),
exprA.Parameters);
Console.WriteLine(exprA.ToString());
Console.WriteLine(exprB.ToString());
Console.WriteLine(exprC.ToString());
Func< int,bool> funcA = exprA.Compile();
Func< int,bool> funcB = exprB.Compile();
Func< int,bool> funcC = exprC.Compile();
Debug.Assert(funcA(3)&!funcA(4)&!funcA(5));
Debug.Assert(!funcB(3)&& funcB(4)&!funcB(5));
Debug.Assert(funcC(3)&&funcC(4)&!funcC(5));
}
}
}


I am trying to build an expression tree programmatically.

I have in my input, a list of condition classes which have the following form:

public class Filter
{
    public string field { get; set; }
    public string operator { get; set; }
    public string value { get; set; }
}

When I build the Expression object I create an Expression for every condition in the following way

foreach ( Filter sf in rules ) {
    Expression ex = sf.ToExpression( query );
    if ( mainExpression == null ) {
        mainExpression = ex;
    }
    else {
        if ( logicalCondition == "AND" ) {
            mainExpression = Expression.And( mainExpression, ex );
        }
        else if ( logicalCondition == "OR" ) {
            mainExpression = Expression.Or( mainExpression, ex );
        }
    }
}

The Filter.ToExpression() method is implemented like this

public override Expression ToExpression( IQueryable query ) {
    ParameterExpression parameter = Expression.Parameter( query.ElementType, "p" );
    MemberExpression memberAccess = null;
    foreach ( var property in field.Split( '.' ) )
        memberAccess = MemberExpression.Property( memberAccess ?? ( parameter as Expression ), property );
    ConstantExpression filter = Expression.Constant( Convert.ChangeType( value, memberAccess.Type ) );
    WhereOperation condition = (WhereOperation)StringEnum.Parse( typeof( WhereOperation ), operator );
    LambdaExpression lambda = BuildLambdaExpression( memberAccess, filter, parameter, condition, value );
    return lambda;
}

Everything works when I have a single condition but when I try to combine expressions using one of the And, Or, AndAlso, OrElse static methods I receive an InvalidOperationException that says:

The binary operator Or is not defined for the types 'System.Func2[MyObject,System.Boolean]' and 'System.Func2[MyObject,System.Boolean]'.

I am getting a little bit confused. Can somebody better explain the reasons of the exception and suggest a solution?

Thanks very much!

解决方案

You're combining a => a == 3 and a => a == 4 into (a => a == 3) || (a => a == 4), but you should instead be trying to make it a => (a == 3 || a == 4). This is not too hard to do manually, but someone has done it for you already. Look for "Combining Expressions".

Edit: as requested, a simple example of how to do this manually.

Edit 2: it uses ExpressionVisitor which is new to .NET 4, but at MSDN you can find a usable implementation for earlier versions. I'm assuming MSDN code doesn't qualify as "third party" for your purposes. You only need to change the protected virtual Expression Visit(Expression exp) method to public. And as Enumerable.Zip is unavailable for you and it isn't necessary, it is gone now.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;

namespace DemoApp
{
    <include ExpressionVisitor definition here for .NET 3.5>

    public class ExpressionParameterReplacer : ExpressionVisitor
    {
        public ExpressionParameterReplacer(IList<ParameterExpression> fromParameters, IList<ParameterExpression> toParameters)
        {
            ParameterReplacements = new Dictionary<ParameterExpression, ParameterExpression>();
            for (int i = 0; i != fromParameters.Count && i != toParameters.Count; i++)
                ParameterReplacements.Add(fromParameters[i], toParameters[i]);
        }
        private IDictionary<ParameterExpression, ParameterExpression> ParameterReplacements
        {
            get;
            set;
        }
        protected override Expression VisitParameter(ParameterExpression node)
        {
            ParameterExpression replacement;
            if (ParameterReplacements.TryGetValue(node, out replacement))
                node = replacement;
            return base.VisitParameter(node);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<int, bool>> exprA = a => a == 3;
            Expression<Func<int, bool>> exprB = b => b == 4;
            Expression<Func<int, bool>> exprC =
                Expression.Lambda<Func<int, bool>>(
                    Expression.OrElse(
                        exprA.Body,
                        new ExpressionParameterReplacer(exprB.Parameters, exprA.Parameters).Visit(exprB.Body)),
                    exprA.Parameters);
            Console.WriteLine(exprA.ToString());
            Console.WriteLine(exprB.ToString());
            Console.WriteLine(exprC.ToString());
            Func<int, bool> funcA = exprA.Compile();
            Func<int, bool> funcB = exprB.Compile();
            Func<int, bool> funcC = exprC.Compile();
            Debug.Assert(funcA(3) && !funcA(4) && !funcA(5));
            Debug.Assert(!funcB(3) && funcB(4) && !funcB(5));
            Debug.Assert(funcC(3) && funcC(4) && !funcC(5));
        }
    }
}

这篇关于异常使用OrElse和AndAlso表达式方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆