12

我需要创建一个动态 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

无法跳转到标签“标签”`

怎么了 ?我只需要返回真或假。

4

3 回答 3

20

你需要改变一些事情:

  • 按照 René 的建议,将返回标签放在块表达式中的函数底部。这是您的return陈述将跳转的地方。

  • 将 Lambda 声明为 type Func<int, bool>。由于您想要一个返回值,这需要是一个函数,而不是一个动作。

  • returnTarget将标签声明为 type 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"
    
于 2012-12-03T17:14:48.723 回答
2

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

if (condition)
    return expression1;
else
    return expression2;

您可以将其转换为三元表达式:condition ? expression1 : expression2. Label然后您可以不使用、Return或来创建表达式Goto

Expression condition;
Expression expression1;
Expression expression2;
/* ... */
Expression body = Expression.Condition(
    test:    condition,
    ifTrue:  expression1,
    ifFalse: expression2);
于 2019-05-13T08:50:46.647 回答
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- 显然,您也想返回一个值,让我看看,至少,它应该是 aFunc而不是 an Action

于 2012-12-03T17:03:56.973 回答