2008-09-10 1 views
11

2つのLinq式の結果を合成したいと思います。彼らは、だから私は作曲したい2の両方がブール値を返すこと(タイプTの)パラメータに、本質的に委譲しているフォーム既存のLinq式を作成するには

Expression<Func<T, bool>> 

に存在します。私が構成したいと思う結果は、ブーリアンの論理的評価でしょう。私は周りつついている

Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; 
Expression<Func<User, bool>> expression2 = t => t.Age == 28; 
Expression<Func<User, bool>> composedExpression = expression1.And(expression2); 

以降に私のコードで私は合成表現

var user = new User(); 
bool evaluated = composedExpression.Compile().Invoke(user); 

を評価したい:私の構文のようなものになるだろうので、私はおそらく、拡張メソッドとしてそれを実装しいくつかの異なるアイデアがありますが、私はそれが私が望んでいたよりも複雑であることを恐れています。これはどうですか?

答えて

17

例です。

var user1 = new User {Name = "steve", Age = 28}; 
var user2 = new User {Name = "foobar", Age = 28}; 

Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; 
Expression<Func<User, bool>> expression2 = t => t.Age == 28; 

var invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); 

var result = Expression.Lambda<Func<User, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters); 

Console.WriteLine(result.Compile().Invoke(user1)); // true 
Console.WriteLine(result.Compile().Invoke(user2)); // false 

あなたが拡張メソッドを経由して、このコードを再利用することができます

class User 
{ 
    public string Name { get; set; } 
    public int Age { get; set; } 
} 

public static class PredicateExtensions 
{ 
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1,Expression<Func<T, bool>> expression2) 
    { 
    InvocationExpression invokedExpression = Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); 

    return Expression.Lambda<Func<T, bool>>(Expression.And(expression1.Body, invokedExpression), expression1.Parameters); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
    var user1 = new User {Name = "steve", Age = 28}; 
    var user2 = new User {Name = "foobar", Age = 28}; 

    Expression<Func<User, bool>> expression1 = t => t.Name == "steve"; 
    Expression<Func<User, bool>> expression2 = t => t.Age == 28; 

    var result = expression1.And(expression2); 

    Console.WriteLine(result.Compile().Invoke(user1)); 
    Console.WriteLine(result.Compile().Invoke(user2)); 
    } 
} 
1

なぜExpression.Andを使用し、その結果のBinaryExpressionを扱ってみませんか?

Expression<Func<T, bool>> expr1 = t => t.Name == "steve"; 
Expression<Func<T, bool>> expr2 = t => t.Age == 28; 
Expression composed = Expression.And(expr1.Body, expr2.Body); 

、あなたはもちろん、ご希望の署名を得るために、ラムダにこれをバンドルすることができますが、これは高価であり、唯一の一度行われるべきでない複数回:

Expression<Func<T, bool>> result = Expression.Lambda<Func<T, bool>>(
    expr, Expression.Parameter(typeof(T), "t") 
); 

/EDIT:あなたができますもちろん、以下のようにラムダを組み合わせますが、これには冗長なコンパイルと関数呼び出しが含まれます:

Expression<Func<string, bool>> z = t => expr1.Compile()(t) && expr2.Compile()(t); 

いいえ、メンテナンスのダウンタイム。投稿全体をもう一度入力しなければならなかった。 :/

/EDIT:あくさんの右ですが、 expr2を個別に呼び出さなければなりません。そうしないと、コンパイラーはパラメーター参照を見つけられません。ここで

関連する問題