Frage

Ich habe mehrere Expression<Func<User,bool>> Ausdrücke, die Eigenschaften teilt. Zum Beispiel:

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";

Gibt es einen einfachen Weg, um die u.IsActive && u.Group != "PROCESS" in einer Variablen zu setzen und es in e1, e2 und e3 verwenden? Editiert:. Und ich will immer noch den gleichen Baum

Es scheint, ich es durch den Bau der Ausdruck mit Expression.Lambda<Func<User, bool>>(BinaryExpression.AndAlso( etc tun kann ... Aber anstatt meinen Code vereinfacht es machte es schwieriger zu lesen.

War es hilfreich?

Lösung

Ich glaube, es gibt keinen Weg, dass sauberer für Ihren Fall zu tun. Sie können BinaryExpression verwenden, wie Sie erwähnt. Sie können die BinaryExpression und Expression.Lambda ruft in eine Methode kapseln und rufen stattdessen (wie PredicateBuilder.And ), aber keiner von denen sind so sauber wie die aktuelle Syntax IMO.

Andere Tipps

Problem mit Lambda-Ausdrücke ist, dass sie unveränderlich sind und Sie können Parameter von Lambda nicht leicht ersetzen. Meine ursprüngliche Idee war, so etwas wie diese ( leider wird dies nicht funktionieren ) zu tun:

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

und Verwendung in Code:

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

Mögliche Lösung

Sie können versuchen Sie eine des Projektes zur Umsetzung Expression Builder Ziel zu verwenden. Ich habe keinen von ihnen verwendet, aber Google gibt viele Verbindungen, zum Beispiel:

Ein weiterer Ansatz

Wenn Sie diese Ausdrücke in LINQ verwenden Werte zu filtern, können Sie Benutzer anderer Ansatz (nicht Ausdrücke kombinieren, sondern kombinieren Filter):

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

Ich glaube nicht, dass es unbedingt eine bessere Antwort als die, die Sie bereits verwenden sind. Wie Mehrdad erwähnt, müssen Sie einen tieferen Baum mit einem Binary zu bauen, und ich denke, dass ein Schritt zurück in der Lesbarkeit von Ihrem aktuellen Code sein würde.

Je nach Nutzung, Sie Macht Lage sein, einige Zeilen Code zu speichern, indem Schließung Semantik zu nutzen und so etwas wie dies zu tun:

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

... aber ob das jede Nutzung hängt davon ab, was Sie mit dem kompilierten Delegierten tun. Können Sie völlig nutzlos sein, aber eine Erwähnung für alle Fälle wert!

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";
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top