8

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"))}

この2つの表現から作りたい

 BinaryExpression be = {tag=>((tag.id=2)||(tag.id=3))} && 
                       {tag=>((tag.uid="MU")||(tag.uid="ST"))} 

LINQのwhere句に渡すことができるこのようなもの。

Expression.And(leftexp、rightexp)を使ってみました

しかし、エラーが発生しました。

二項演算子Andは、タイプ
'System.Func 2[WebApplication1.View_MyView,System.Boolean]' and 'System.Func2 [WebApplication1.View_MyView、System.Boolean]'に対して定義されていません。

式は私にとって新しいものであり、あまりにも多くのコードを調べた可能性があるため、これを行う方法に少し混乱しています...正しい方向に私を向けることができれば本当にありがたいです。

4

2 に答える 2

8

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、そのソースは少し前にここで公開されていました。私たちのライブラリは、.NET4に移行するまでその実装を使用していました。

于 2012-10-04T21:58:16.880 に答える
1

両方の完全な式ツリーを完全に新しいものに書き直さずにそれを行うことはできません。

理由:パラメータ式オブジェクトは、式ツリー全体で同じである必要があります。2つを組み合わせると、同じパラメーターに対して2つのパラメーター式オブジェクトがあり、機能しません。

次のコードで表示されます。

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>>(...)呼び出しに指定されたものと一致する必要があるパラメーター式オブジェクトがあります。

これを解決するには、パラメータータグの新しい(単一の)パラメーター式を使用して完全な式を再作成します。

問題の詳細については、ここを参照してください。

于 2012-10-02T06:04:53.803 に答える