13

I need to create a dynamic linq expression an i started work with many examples. I tested some and some work and some not. In this case i want to create a method that looks like :

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

Now i have written the following :

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

Now it throws InvalidOperationException:

Cannot jump to the label "label"`

What is wrong ? I only need a return true or false.

1
  • 1
    Can you tell us a little more about what you are trying to achieve? For example why do you need to dynamically create this expression... and why do you need to use labels and if\else when you could write: public bool Check(int intvar) { return i > 2; } Commented Dec 3, 2012 at 16:57

3 Answers 3

20

You need to change a few things:

  • Put the return label at the bottom of your function in a block expression, as René suggested. This is where your return statement will jump.

  • Declare the Lambda as type Func<int, bool>. Since you want a return value, this needs to be a function, not an action.

  • Declare the returnTarget label as type bool. Since the return value of a block expression is the value of its last statement, the label must be of the correct type.

  • Provide a default value for the final label (= the return value of your function if the label is reached by normal control flow instead of a return statement).

    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"
    
Sign up to request clarification or add additional context in comments.

1 Comment

If you look at some compiled IL-code, you can see that it never really left... ;)
4

If you have simple condition statement like this:

if (condition)
    return expression1;
else
    return expression2;

You can transform that into ternary expression: condition ? expression1 : expression2. And then you can create an expression without using Label, Return, or Goto.

Expression condition;
Expression expression1;
Expression expression2;
/* ... */
Expression body = Expression.Condition(
    test:    condition,
    ifTrue:  expression1,
    ifFalse: expression2);

Comments

1

returnTarget currently is only referenced by your if/then/else statement. The label is not placed in the statement anywhere. So it does not know where to jump to. The label is only defined and referenced, but not placed.

Try using Expression.Block to combine your lambda and your label.

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

Haven't tested it, but this is the general direction in which you can find your answer.

-update- tested it, the lambda above compiles and runs just fine as it stands now.

-update2- apparantly, you want to return a value as well, let me have a look, at the least, it should be a Func rather than an Action.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.