2012-12-03 6 views
9

많은 예제로 작업을 시작한 동적 linq 표현식을 작성해야합니다. 나는 약간과 약간의 일을 시험했고, 그렇지 않은 것을 시험했다.반환 값이있는 동적 Linq 표현

레이블로 점프 할 수 없습니다

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 예외 :

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

지금은 다음과 같은 것이 작성한이 경우 내가처럼 보이는 방법을 만들려면 "label"`

무엇이 잘못 되었나요? 나는 진실하거나 틀린 반환 만하면된다.

+0

당신은 우리에게 당신이 달성하려고하는 일에 대해 좀 더 말씀해 주시겠습니까? 예를 들어, 왜이 표현식을 동적으로 생성해야합니까? 왜 쓸 수있을 때 레이블 및 if \ else를 사용해야합니까? public bool Check (int intvar) { return i> 2; } –

답변

14

당신은 몇 가지를 변경해야 르네가 제안

  • 는 블록 식에 함수의 하단에 반환 라벨을 넣습니다. 이것은 귀하의 return 성명이 점프하는 곳입니다.

  • 람다를 Func<int, bool>으로 선언하십시오. 반환 값을 원하기 때문에이 값은 함수가 아닌 액션이어야합니다.

  • bool으로 returnTarget 레이블을 선언하십시오. 블록 표현식의 리턴 값은 마지막 명령문의 값이기 때문에 레이블은 올바른 유형이어야합니다.

  • 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

컴파일 된 일리노이 코드를 살펴보면 그 코드가 실제로는 남지 않았 음을 알 수 있습니다.;) –

1

returnTarget은 현재 if/then/else 문에 의해서만 참조됩니다. 레이블은 아무 곳에 나내어 놓지 않습니다. 따라서 어디로 뛰어 오르는 지 알지 못합니다. 레이블은 정의되고 참조되지만 배치되지는 않습니다.

Expression.Block을 사용하여 람다와 라벨을 결합 해보십시오.

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

테스트하지는 않았지만 답변을 찾을 수있는 일반적인 방향입니다.

- 업데이트 됨, 위의 람다는 컴파일되어 현재 그대로 유지됩니다.

-update2- apparantly, 당신은 값을 반환하고 싶습니다. 최소한보십시오, Action이 아닌 Func이어야합니다.