AJ1*_*J17 8 c# expression-trees
我正在尝试使用LINQ为我的视图创建一个where子句.
我能够创建单列where子句,我想现在创建多个列where子句..
我已经看到了在.Net 4及更高版本中实现的代码,但由于我必须使用.Net 3.5,我需要快速解决这个问题.所以我想做的是....
Expression leftexp = {tag=>((tag.id=2)||(tag.id=3))}
Expression rightexp = {tag=>((tag.uid="MU")||(tag.uid="ST"))}
Run Code Online (Sandbox Code Playgroud)
从我想创建的这两个表达式
BinaryExpression be = {tag=>((tag.id=2)||(tag.id=3))} &&
{tag=>((tag.uid="MU")||(tag.uid="ST"))}
Run Code Online (Sandbox Code Playgroud)
这样的东西,我可以传递给LINQ中的where子句.
我试着用Expression.And(leftexp,rightexp)
但得到了错误..
二进制运算符And没有为类型
System.Func2[WebApplication1.View_MyView,System.Boolean]' and 'System.Func2 [WebApplication1.View_MyView,System.Boolean]'定义.
表达对我来说是新的,可能已经看了太多的代码,所以有点混淆如何去做...如果你能指出我正确的方向,真的很感激.
通过将ExpressionVisitor添加到BCL,重写表达式变得容易.有了一些助手,任务变得几乎无足轻重.
这是我用来将委托应用于树节点的访问者类:
internal sealed class ExpressionDelegateVisitor : ExpressionVisitor {
private readonly Func<Expression , Expression> m_Visitor;
private readonly bool m_Recursive;
public static Expression Visit ( Expression exp , Func<Expression , Expression> visitor , bool recursive ) {
return new ExpressionDelegateVisitor ( visitor , recursive ).Visit ( exp );
}
private ExpressionDelegateVisitor ( Func<Expression , Expression> visitor , bool recursive ) {
if ( visitor == null ) throw new ArgumentNullException ( nameof(visitor) );
m_Visitor = visitor;
m_Recursive = recursive;
}
public override Expression Visit ( Expression node ) {
if ( m_Recursive ) {
return base.Visit ( m_Visitor ( node ) );
}
else {
var visited = m_Visitor ( node );
if ( visited == node ) return base.Visit ( visited );
return visited;
}
}
}
Run Code Online (Sandbox Code Playgroud)
以下是简化重写的辅助方法:
public static class SystemLinqExpressionsExpressionExtensions {
public static Expression Visit ( this Expression self , Func<Expression , Expression> visitor , bool recursive = false ) {
return ExpressionDelegateVisitor.Visit ( self , visitor , recursive );
}
public static Expression Replace ( this Expression self , Expression source , Expression target ) {
return self.Visit ( x => x == source ? target : x );
}
public static Expression<Func<T , bool>> CombineAnd<T> ( this Expression<Func<T , bool>> self , Expression<Func<T , bool>> other ) {
var parameter = Expression.Parameter ( typeof ( T ) , "a" );
return Expression.Lambda<Func<T , bool>> (
Expression.AndAlso (
self.Body.Replace ( self.Parameters[0] , parameter ) ,
other.Body.Replace ( other.Parameters[0] , parameter )
) ,
parameter
);
}
}
Run Code Online (Sandbox Code Playgroud)
这允许组合这样的表达式:
static void Main () {
Expression<Func<int , bool>> leftExp = a => a > 3;
Expression<Func<int , bool>> rightExp = a => a < 7;
var andExp = leftExp.CombineAnd ( rightExp );
}
Run Code Online (Sandbox Code Playgroud)
更新:
在情况下ExpressionVisitor的不可用,它的来源已经出版前一段时间在这里.我们的库使用了该实现,直到我们迁移到.NET 4.
如果不将两个完整的表达式树重写为一个全新的表达式树,就无法做到这一点。
原因:整个表达式树的参数表达式对象必须相同。如果将两者结合起来,就会有同一个参数的两个参数表达式对象,这是行不通的。
它用以下代码显示:
Expression<Func<Tab, bool>> leftexp = tag => ((tag.id == 2) || (tag.id == 3));
Expression<Func<Tab, bool>> rightexp = tag => ((tag.uid == "MU") || (tag.uid == "ST"));
Expression binaryexp = Expression.AndAlso(leftexp.Body, rightexp.Body);
ParameterExpression[] parameters = new ParameterExpression[1] {
Expression.Parameter(typeof(Tab), leftexp.Parameters.First().Name)
};
Expression<Func<Tab, bool>> lambdaExp = Expression.Lambda<Func<Tab, bool>>(binaryexp, parameters);
var lambda = lambdaExp.Compile();
Run Code Online (Sandbox Code Playgroud)
这在 lambdaExp.Compile() 调用上失败,并给出以下异常:
Lambda Parameter not in scope
Run Code Online (Sandbox Code Playgroud)
这是因为基本上我重复使用了 leftexp 和 rightexp 表达式,但它们有不同的参数表达式,这两个表达式都不是我给调用的Expression.Lambda<Func<Tab>>(...)。在 leftexp 和 rightexp 的深处有一些参数表达式对象,它们必须与调用时给出的对象相匹配Expression.Lambda<Func<Tab>>(...)。
为了解决这个问题,您必须使用参数标记的新(单个)参数表达式重新创建完整的表达式。
有关该问题的更多信息,请参阅此处。
| 归档时间: |
|
| 查看次数: |
5889 次 |
| 最近记录: |