Dynamischer Linq-Ausdruck mit Rückgabewert

c# expression-trees

Frage

Ich muss einen dynamischen linq-Ausdruck erstellen und ich fing an, mit vielen Beispielen zu arbeiten. Ich testete einige und einige arbeiten und manche nicht. In diesem Fall möchte ich eine Methode erstellen, die wie folgt aussieht:

public bool Check(int intvar)
{
   if ( i > 2 )
     return true;
   else
     return false;
}

Jetzt habe ich Folgendes geschrieben:

LabelTarget returnTarget = Expression.Label("label");
ParameterExpression para = Expression.Parameter(typeof(int), "intvalue");
Expression test = Expression.GreaterThan(para, Expression.Constant(5));
Expression iftrue = Expression.Return(returnTarget, Expression.Constant(true));
Expression iffalse = Expression.Return(returnTarget,                   Expression.Constant(false));
Expression.IfThenElse(test, iftrue, iffalse);

this.TheExpression = Expression.IfThenElse(test, iftrue, iffalse);
Expression.Lambda<Action<int>>(
this.TheExpression,
new ParameterExpression[] { para }
).Compile()(5);

Jetzt wird die InvalidOperationException :

Kann nicht zum Label "label" springen

Was ist falsch ? Ich brauche nur eine Rückkehr wahr oder falsch.

Akzeptierte Antwort

Sie müssen ein paar Dinge ändern:

  • Setzen Sie das Rückgabe-Label am Ende Ihrer Funktion in einen Block-Ausdruck, wie René vorgeschlagen hat. Dies ist, wo Ihre return Anweisung springt.

  • Deklariere das Lambda als Typ Func<int, bool> . Da Sie einen Rückgabewert wünschen, muss dies eine Funktion und keine Aktion sein.

  • Deklarieren Sie das returnTarget Label als Typ bool . Da der Rückgabewert eines Blockausdrucks der Wert seiner letzten Anweisung ist, muss das Label vom richtigen Typ sein.

  • Geben Sie einen Standardwert für die endgültige Beschriftung an (= der Rückgabewert Ihrer Funktion, wenn die Beschriftung vom normalen Steuerungsfluss anstelle einer return ).

    LabelTarget returnTarget = Expression.Label(typeof(bool));
    ParameterExpression para = Expression.Parameter(typeof(int), "intvalue");
    Expression test = Expression.GreaterThan(para, Expression.Constant(5));
    Expression iftrue = Expression.Return(returnTarget, Expression.Constant(true));
    Expression iffalse = Expression.Return(returnTarget, Expression.Constant(false));
    
    var ex = Expression.Block(
        Expression.IfThenElse(test, iftrue, iffalse),
        Expression.Label(returnTarget, Expression.Constant(false)));
    
    var compiled = Expression.Lambda<Func<int, bool>>(
        ex,
        new ParameterExpression[] { para }
    ).Compile();
    
    Console.WriteLine(compiled(5));     // prints "False"
    Console.WriteLine(compiled(6));     // prints "True"
    

Beliebte Antwort

returnTarget derzeit nur von Ihrer if / then / else-Anweisung referenziert. Das Label wird nirgendwo in der Anweisung platziert. Es weiß also nicht, wohin man springt. Das Label ist nur definiert und referenziert, aber nicht platziert.

Verwenden Sie Expression.Block , um Ihr Lambda und Ihr Label zu kombinieren.

Expression.Lambda<Action<int>>(
    Expression.Block(
        this.TheExpression,
        Expression.Label(returnTarget)
    ),
    new ParameterExpression[] { para }
    ).Compile()(5);

Habe es nicht getestet, aber das ist die allgemeine Richtung, in der du deine Antwort finden kannst.

-update- testete es, das obige Lambda kompiliert und läuft prima, wie es jetzt steht.

-update2- Sie wollen auch einen Wert zurückgeben, lassen Sie mich einen Blick darauf werfen, zumindest sollte es eher eine Func als eine Action .



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow