Es konnte kein zusammengesetzter Ausdruck erstellt werden > aus einer Reihe von Ausdrücken

.net c# expression expression-trees

Frage

(Antwort nach unten)

Ich versuche ein System zu erstellen, das kombiniert

Func<T, bool> 

delegiert in einen ExpressionTree, der es mir erlaubt, einen Wert (in diesem Fall badValue) zu übergeben und einen bool out zu erhalten, wenn alle Prädikate true zurückgeben und die binären Operationen berücksichtigt werden. Dies ist das erste Mal, dass ich Expression / ExpressionTrees verwende, also sei bitte sanft.

Ich erhalte diesen Fehler:

ArgumentException: Ausdruck vom Typ 'System.Boolean' kann nicht aufgerufen werden

in dieser Zeile:

collectAnswers = Expression.And(isEmpty.Body, Expression.Invoke(...

Ich habe diese Zeile so eingerichtet, weil ich den Verweis auf den value unter allen Ausdrücken teilen muss (richtig?).

Mein ideales Szenario ist, nur eine Menge zu haben

Expression<Func<blah, blah, bool>> 

und ich kann diese zusammen mit logischen Operatoren (And / Or / Not) in ein System einfügen und am Ende einen Booler herausholen. In der Hoffnung, ein dynamisches Erstellen von Regeln zu ermöglichen, die ein Wert durchlaufen muss.

Ist das überhaupt möglich in der Route, die ich gehe? Wenn nicht, würden ein paar Hinweise, die mich auf den richtigen Weg leiten, geschätzt werden.

string badValue = "hello!";
const int minSize = 8;
const int maxSize = 30;

Expression<Func<string, bool>> stringLengthMax = value => value.Length < maxSize;
Expression<Func<string, bool>> stringLengthMin = value => value.Length > minSize;
Expression<Func<string, bool>> isEmpty = value => !string.IsNullOrEmpty(value);

BinaryExpression collectAnswers = Expression.And(stringLengthMax.Body, Expression.Invoke(stringLengthMin, stringLengthMax.Parameters));
collectAnswers = Expression.And(isEmpty.Body, Expression.Invoke(collectAnswers, stringLengthMax.Parameters));

Func<string, bool> shouldValidate = Expression.Lambda<Func<string, bool>>(collectAnswers, stringLengthMax.Parameters).Compile();
bool result = shouldValidate(badValue);

Antwort Ich habe den / die Parameter nicht richtig durchgespielt, unten ist ein Beispiel für mehrere Parameter, die unter mehreren Expressions aufgeteilt sind, die in einen ExpressionTree eingefügt werden, und ein einzelner Boolescher Wert kommt aus dem kompilierten Func, isValid

const int minSize = 8;
const int maxSize = 30;

Expression<Func<string, int, bool>> stringLengthMax = (value, max) => value.Length <= max;
Expression<Func<string, int, bool>> stringLengthMin = (value, min) => value.Length >= min;
Expression<Func<string, bool>> isEmpty = value => string.IsNullOrEmpty(value);

ParameterExpression valueParameter = Expression.Parameter(typeof(string));
ParameterExpression minParameter = Expression.Parameter(typeof(int));
ParameterExpression maxParameter = Expression.Parameter(typeof(int));

Expression<Func<string, int, int, bool>> minMaxCheck =
    Expression.Lambda<Func<string, int, int, bool>>(
        Expression.And(Expression.Invoke(stringLengthMax, valueParameter, maxParameter), 
            Expression.Invoke(stringLengthMin, valueParameter, minParameter)), valueParameter, minParameter, maxParameter);

minMaxCheck = Expression.Lambda<Func<string, int, int, bool>>(
    Expression.And(Expression.Invoke(minMaxCheck, valueParameter, minParameter, maxParameter), 
        Expression.Not(Expression.Invoke(isEmpty, valueParameter))), valueParameter, minParameter, maxParameter);

Func<string, int, int, bool> isValid = minMaxCheck.Compile();
bool resultFalse1 = isValid("hello!", minSize, maxSize); // false - too short
bool resultTrue1 = isValid("hello!", "hello!".Length, maxSize); // true - adjust min
bool resultFalse2 = isValid("1234567890123456789012345678901", minSize, maxSize); // false - too long
bool resultTrue2 = isValid("1234567890123456789012345678901", minSize, "1234567890123456789012345678901".Length); // true - adjust max
bool resultFalse3 = isValid(string.Empty, minSize, maxSize); // false - empty
bool shouldBeTrue = isValid("1234567890", minSize, maxSize); // true - just right
bool resultFalse4 = isValid("1234567890", maxSize, maxSize); // false - adjust min
bool resultFalse5 = isValid("1234567890", minSize, minSize); // false - adjust max

Akzeptierte Antwort

Wenn Sie das mit Expressions machen wollten, würde so etwas funktionieren. Das ist kein Kurzschluss, obwohl du das einbauen kannst. Du warst ziemlich nah dran. Sie müssen einen Parameterausdruck durch den gesamten Parameterbaum führen.

string badValue = "hello!";
const int minSize = 8;
const int maxSize = 30;

Expression<Func<string, bool>> stringLengthMax = value => value.Length < maxSize;
Expression<Func<string, bool>> stringLengthMin = value => value.Length > minSize;
Expression<Func<string, bool>> isEmpty = value => !string.IsNullOrEmpty(value);

ParameterExpression pe = Expression.Parameter(typeof(string));

var x = Expression.Lambda<Func<string, bool>>(
    Expression.And(Expression.Invoke(stringLengthMax, pe), 
        Expression.And(Expression.Invoke(stringLengthMin, pe), Expression.Invoke(isEmpty, pe))), pe);

Func<string, bool> shouldValidate = x.Compile();
bool resultFalse1 = shouldValidate("hello!");
bool resultFalse2 = shouldValidate("1234567890123456789012345678901");
//bool resultFalse3 = shouldValidate(null); Throws an exception because you can't do (null).Length
bool shouldBeTrue = shouldValidate("123456789");

//LinqPad code to view results:
resultFalse1.Dump();
resultFalse2.Dump();
//resultFalse3.Dump();
shouldBeTrue.Dump();

Beliebte Antwort

Es scheint mir, dass Sie nicht wirklich einen Ausdrucksbaum erstellen müssen. Sie können Ihre funcs mit einer einfachen linq kombinieren (definieren Sie sie als Func<string, bool> , nicht Expression<Func<string, bool>> ):

Func<string, bool> shouldValidate = 
    arg => new[] {stringLengthMax, stringLengthMin, isEmpty}.All(func => func(arg));

Wenn Sie mehr als nur and möchten, können Sie Ihre Funktionen logisch kombinieren:

Func<string, bool> shouldValidate = 
    arg => isEmpty(arg) || (stringLengthMax(arg) && stringLengthMin(arg));


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum