我正在嘗試使用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"))}
從我想創建的這兩個表達式
BinaryExpression be = {tag=>((tag.id=2)||(tag.id=3))} &&
{tag=>((tag.uid="MU")||(tag.uid="ST"))}
像這樣的東西,我可以傳遞給LINQ中的where子句。
我試著用Expression.And(leftexp,rightexp)
但得到了錯誤..
二進制運算符And沒有為類型定義
'System.Func2[WebApplication1.View_MyView,System.Boolean]' and 'System.Func
2 [WebApplication1.View_MyView,System.Boolean]'。
表達對我來說是新的,可能已經看了太多的代碼,所以有點混淆如何去做...如果你能指出我正確的方向,真的很感激。
如果不將完整的表達式樹重寫為一個完整的表達式樹,則無法做到這一點。
原因:整個表達式樹的參數表達式對象必須相同。如果將兩者結合使用,則同一參數有兩個參數表達式對象,這些對象無效。
它顯示以下代碼:
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();
這在lambdaExp.Compile()調用上失敗,它給出了以下異常:
Lambda Parameter not in scope
這是因為基本上我正在重新使用leftexp和rightexp表達式,但是它們有不同的參數表達式,這些都不是由我給Expression.Lambda<Func<Tab>>(...)
打電話。在leftexp和rightexp中,有一些參數表達式對象必須與Expression.Lambda<Func<Tab>>(...)
調用的對象匹配。
要解決此問題,您需要使用參數標記的新(單個)參數表達式重新創建完整的表達式。
有關該問題的詳細信息,請參見此處 。
通過在BCL中添加ExpressionVisitor,可以更輕鬆地重寫表達式。在一些幫助者的幫助下,這項任務變得微不足道了。
這是一個我用來將委託應用於樹節點的訪問者類:
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;
}
}
}
以下是簡化重寫的輔助方法:
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
);
}
}
它允許組合這樣的表達式:
static void Main () {
Expression<Func<int , bool>> leftExp = a => a > 3;
Expression<Func<int , bool>> rightExp = a => a < 7;
var andExp = leftExp.CombineAnd ( rightExp );
}
更新:
如果ExpressionVisitor
不可用,它的來源已經在此處發布了。在遷移到.NET 4之前,我們的庫一直使用該實現。