2012-12-03 80 views
9

我需要创建一个动态LINQ表达式,我开始使用很多示例。我测试了一些和一些工作,有些则没有。在这种情况下,我想建立这样一个方法:动态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

不能跳转到标签“标签”

什么是错的?我只需要一个真或假的回报。

+0

你能告诉我们一点关于你想达到什么目的?例如,为什么你需要动态创建这个表达式......为什么你需要使用标签,如果\ else当你可以写: public bool Check(int intvar) { return i> 2; } –

回答

14

你需要改变一些东西:

  • 将返回标签在你的底层函数块中的表达,如勒建议。这是您的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

谢谢。做得好。所以goto运算符是重生的。 ;-)。 – sven

+6

如果你看看一些编译的IL代码,你可以看到它从来没有真的离开......;) –

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