具有返回值的动态Linq表达式

时间:2012-12-03 16:50:04

标签: c# expression-trees

我需要创建一个动态的linq表达式,我开始使用很多例子。我测试了一些和一些工作而一些没有。在这种情况下,我想创建一个看起来像这样的方法:

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

现在我写了以下内容:

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

现在抛出InvalidOperationException

  

无法跳转到标签&#34;标签&#34;`

有什么问题?我只需要返回真或假。

3 个答案:

答案 0 :(得分:18)

你需要改变一些事情:

  • 如René建议的那样,将函数底部的返回标签放在块表达式中。这是您的return语句将跳转的地方。

  • 将Lambda声明为Func<int, bool>类型。由于您需要返回值,因此这需要是一个函数,而不是一个操作。

  • returnTarget标签声明为bool类型。由于块表达式的返回值是其最后一个语句的值,因此标签必须是正确的类型。

  • 为最终标签提供默认值(=如果通过正常控制流而不是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"
    

答案 1 :(得分:1)

returnTarget目前仅由if / then / else语句引用。标签不会放在任何地方的声明中。所以它不知道去哪里。标签仅定义和引用,但未放置。

尝试使用Expression.Block合并您的lambda和标签。

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

尚未测试过,但这是您找到答案的一般方向。

-update-测试它,上面的lambda编译并运行就好了。

-update2-显然,你想要返回一个值,让我看看,至少,它应该是Func而不是Action

答案 2 :(得分:0)

如果您有这样的简单条件语句:

listOfObjects

您可以将其转换为三元表达式:if (condition) return expression1; else return expression2; 。 然后您可以创建表达式而无需使用condition ? expression1 : expression2LabelReturn

Goto