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ます:

ラベル「label」`にジャンプできません

なにが問題ですか ?trueまたはfalseを返すだけで済みます。

4

3 に答える 3

20

いくつか変更する必要があります。

  • Renéが提案したように、関数の下部にあるリターンラベルをブロック式に配置します。これはあなたのreturnステートメントがジャンプするところです。

  • ラムダをタイプとして宣言し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"
    
于 2012-12-03T17:14:48.723 に答える
2

このような単純な条件ステートメントがある場合:

if (condition)
    return expression1;
else
    return expression2;

これを3値式に変換できます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ラムダとラベルを組み合わせて使用​​してみてください。

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

それをテストしていませんが、これはあなたがあなたの答えを見つけることができる一般的な方向です。

-update-テスト済みです。上記のラムダはコンパイルされ、現在の状態で正常に実行されます。

-update2-どうやら、あなたも値を返したいのですが、少なくとも、Funcではなくである必要がありActionます。

于 2012-12-03T17:03:56.973 に答える