而且在几个表达式< Func< T,bool>>之间:从范围引用 [英] AndAlso between several Expression<Func<T, bool>> : referenced from scope

查看:132
本文介绍了而且在几个表达式< Func< T,bool>>之间:从范围引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有3个谓词,我想要一个 AndAlso 之间。我在板上找到了几个样本,但是无法解决我的问题。



这些谓词是:表达式< Func< T,bool>> ;



我有这个代码:

 表达式< Func< T,bool>>谓词1 = ......; 
表达式< Func< T,bool>>>谓词2 = ......;
表达式< Func< T,bool>>>谓词3 = ......;

我创建一个扩展方法来创建一个AndAlso:

  public static Expression< Func< T,bool>> AndAlso< T>(
此表达式< Func< T,bool>>> expr,
表达式< Func< T,bool>> exprAdd)
{
var param = Expression.Parameter(typeof(T),p);
var predicateBody = Expression.AndAlso(expr.Body,exprAdd.Body);
return Expression.Lambda< Func< T,bool>>(predicateBody,param);

//尝试过这个
// var body = Expression.AndAlso(expr.Body,exprAdd.Body);
//返回Expression.Lambda< Func< T,bool>>(body,expr.Parameters [0]);
}

我使用如下:

  var finalPredicate = predicate1 
.AndAlso< MyClass>(predicate2)
.AndAlso&MyClass>(predicate3);

谓词如下:



当我在查询中使用时:

  var res = myListAsQueryable()。Where(finalPredicate).ToList< MyClass>(); 

我收到此错误:
变量'p'类型为BuilderPredicate MyClass'从范围''引用,但没有定义



你能告诉我怎么了吗?



非常感谢,

解决方案

问题是创建一个新的参数 - 你可以做到这一点,但如果你简单将其分配给最终的lambda,您的参数和提供的表达式中的原始参数之间没有连接。尝试更改表达式的参数名称,然后检查 finalPredicate 。你会看到如下:

  {p => (((x.Age == 42)AndAlso(y.Salary == 50))AndAlso z.FirstName.StartsWith(foo))} 

现在问题应该很明显。



Marc Gravell在这个答案 一般的 Expression.AndAlso ,这正是你需要的:

  public static Expression< Func< T,bool>> AndAlso< T>(
此表达式< Func< T,bool>> expr1,
表达式< Func< T,bool>> expr2)
{
//需要检测他们是否使用相同的
//参数实例;如果没有,他们需要修复
ParameterExpression param = expr1.Parameters [0];
if(ReferenceEquals(param,expr2.Parameters [0]))
{
//简单版本
返回Expression.Lambda }
//否则,保持expr1原样,并调用expr2
返回Expression.Lambda< Func< T,bool>>(
Expression.AndAlso(
expr1.Body,
Expression.Invoke(expr2,param)),param);
}

(Marc,而不是我的代码)


I have 3 predicates, I'd like make an AndAlso between. I found several sample on the board, but can't solve my problem.

These predicates are : Expression<Func<T, bool>>

I have this code :

Expression<Func<T, bool>> predicate1 = ......;
Expression<Func<T, bool>> predicate2 = ......;
Expression<Func<T, bool>> predicate3 = ......;

I create an extension method to make an "AndAlso" :

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr, 
    Expression<Func<T, bool>> exprAdd)
{
    var param = Expression.Parameter(typeof(T), "p");
    var predicateBody = Expression.AndAlso(expr.Body, exprAdd.Body);
    return Expression.Lambda<Func<T, bool>>(predicateBody, param);

    //Tried this too
    //var body = Expression.AndAlso(expr.Body, exprAdd.Body);
    //return Expression.Lambda<Func<T, bool>>(body, expr.Parameters[0]);
}

I use like this :

var finalPredicate = predicate1
    .AndAlso<MyClass>(predicate2)
    .AndAlso<MyClass>(predicate3);

The predicate look this :

When I use in a query :

var res =  myListAsQueryable().Where(finalPredicate).ToList<MyClass>();

I get this error : variable 'p' of type 'BuilderPredicate.MyClass' referenced from scope '', but it is not defined

Could you tell me what's wrong ?

Thanks a lot,

解决方案

The problem is creating a new parameter - you can do that, but if you simply assign it to the final lambda, there's no connection between your parameter and the original parameters in the provided expressions. Try changing param names of the expressions and then check the finalPredicate. You will see something like:

{p => (((x.Age == 42) AndAlso (y.Salary == 50)) AndAlso z.FirstName.StartsWith("foo"))}

The problem should be obvious now.

Marc Gravell suggest in this answer a general Expression.AndAlso, which is exactly what you need:

public static Expression<Func<T, bool>> AndAlso<T>(
    this Expression<Func<T, bool>> expr1,
    Expression<Func<T, bool>> expr2)
{
    // need to detect whether they use the same
    // parameter instance; if not, they need fixing
    ParameterExpression param = expr1.Parameters[0];
    if (ReferenceEquals(param, expr2.Parameters[0]))
    {
        // simple version
        return Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(expr1.Body, expr2.Body), param);
    }
    // otherwise, keep expr1 "as is" and invoke expr2
    return Expression.Lambda<Func<T, bool>>(
        Expression.AndAlso(
            expr1.Body,
            Expression.Invoke(expr2, param)), param);
}

(code by Marc, not me)

这篇关于而且在几个表达式&lt; Func&lt; T,bool&gt;&gt;之间:从范围引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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