7

Expression<Func<User,bool>>プロパティを共有する式がいくつかあります。例えば、

Expression<Func<User, bool>> e1 = 
  (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != null;
Expression<Func<User, bool>> e2 = 
  (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != "A";
Expression<Func<User, bool>> e3 = 
  (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != "B";

u.IsActive && u.Group != "PROCESS"を変数に入れて e1、e2、e3 で使用する簡単な方法はありますか? 編集済み:そして、私はまだ同じツリーが欲しい.

etcで式を作成することでできるようですがExpression.Lambda<Func<User, bool>>(BinaryExpression.AndAlso(、コードを単純化するのではなく、読みにくくしました。

4

4 に答える 4

3

あなたの場合、それを行うためのよりクリーンな方法はないと思います。おっしゃる通り使えますBinaryExpressionBinaryExpressionandExpression.Lambda呼び出しをメソッドにカプセル化し、代わりにそれを呼び出すことができます( PredicateBuilder.Andのように) が、現在の構文 IMO ほどクリーンなものはありません。

于 2009-09-17T13:39:12.797 に答える
3

ラムダ式の問題は、それらが不変であり、ラムダのパラメーターを簡単に置き換えることができないことです。私の最初のアイデアは、次のようなことをすることでした(残念ながら、これはうまくいきません):

public static class ExpressionExtesions
{
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> baseCondition, Expression<Func<T, bool>> additionalCondition)
    {
        var and = Expression.AndAlso(baseCondition.Body, additionalCondition.Body);
        return Expression.Lambda<Func<T, bool>>(and, baseCondition.Parameters);  // additionalCondition.Body still uses its own parameters so this fails on Compile()
    }
}

コードで使用します:

Expression<Func<User, bool>> e = usr => usr.IsActive && usr.Group != "PROCESS";

var e1 = e.And(u => u.Name != null);
var e2 = e.And(u => u.Name != "A");
var e3 = e.And(u => u.Name != "B");

考えられる解決策

式ビルダーの実装を目的としたプロジェクトの 1 つを使用してみることができます。私はそれらのいずれも使用していませんが、Google は多くのリンクを提供しています。たとえば、次のとおりです。

別のアプローチ

LINQ でこれらの式を使用して値をフィルター処理している場合は、別のアプローチを使用できます (式を結合するのではなく、フィルターを結合します)。

var activeUsers = allUsers.Where(usr => usr.IsActive && usr.Group != "PROCESS");

var usersAll = activeUsers.Where(u => u.Name != null);
var usersNotA = activeUsers.Where(u => u.Name != "A");
var usersNotB = activeUsers.Where(u => u.Name != "B");
于 2009-09-17T14:35:45.260 に答える
2

あなたがすでに使っているものよりも良い答えが必ずしもあるとは思いません。Mehrdad が言及しているように、BinaryExpression を使用してより深いツリーを構築する必要があります。これは、現在のコードから読みやすさが後退すると思います。

使い方によっては、クロージャ セマンティクスを利用して次のようにすることで、コードの行数を節約できる場合があります。

string name = null;

Expression<Func<User, bool>> e = 
  (User u) => u.IsActive && u.Group != "PROCESS" && u.Name != name;

var expr = e.Compile();

name = "A";
var result = expr.Invoke(u); //True (assume u.Name = "B")

name = "B";
result = expr.Invoke(u); //False

...しかし、それが使用されるかどうかは、コンパイルされたデリゲートで何をしているかによって異なります。あなたにとってはまったく役に立たないかもしれませんが、念のために言及する価値があります!

于 2009-09-17T13:55:10.440 に答える
1
var test = new Func<User, bool>(u=> u.IsActive && u.Group != "PROCESS");
Expression<Func<User, bool>> e1 = (User u) => test(u) && u.Name != null;
Expression<Func<User, bool>> e2 = (User u) => test(u) && u.Name != "A";
Expression<Func<User, bool>> e3 = (User u) => test(u) && u.Name != "B";
于 2009-09-17T13:30:20.003 に答える