Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Linq Expression with return value

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.

like image 763
sven Avatar asked Dec 03 '12 16:12

sven


People also ask

Can you use LINQ on dynamic?

It's possible to build up dynamic LINQ queries or queries with several conditional criteria. In fact there are several options for doing this, including the use of expression trees.

Can we use dynamic in lambda expression?

In 2010, the Dynamic Type was introduced and that gave us the ability to create dynamic lambda expressions.

What is dynamic LINQ C#?

The Dynamic LINQ library exposes a set of extension methods on IQueryable corresponding to the standard LINQ methods at Queryable, and which accept strings in a special syntax instead of expression trees.


2 Answers

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"
    
like image 148
Heinzi Avatar answered Nov 03 '22 09:11

Heinzi


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);
like image 32
groser Avatar answered Nov 03 '22 11:11

groser