2011-12-16 5 views
11

ためLambdaExpressionにパラメータ名を変更するのは、私はこのような表現を持っているとしましょう:だけ表示

Expression<Predicate<T>> exp 

私は次の式割り当てた場合:

a => a.First() != 0 

をして、私は得ることができますexp.ToString()呼び出しますまさに私が渡した表現ですが、それはまったくいいですが、私たちが 'a'のために使う名前を他のものと変えたいとしたら、どうすればいいですか? 上記の例では文字列の置換はできませんが、パラメータが 'i'などと指定された場合はどうなりますか? パラメータ名の置換、実行時のみを変更することは可能ですか?表現の意味?

UPDATE @PhilKleinは完璧に動作しますが、我々はちょうど公共訪問方法に保護されたから・修正により、Matt WarrenからExpressionVisitorクラスを使用することができますフレームワーク3.5をターゲットにする必要がある場合は、フレームワーク4.しかしが必要です。

+0

なぜ表現が表現と正確に一致しないかを表す文字列を出力したいのか分かりません。なぜあなたはこれをしたいのですか?なぜコードをリファクタリングしたくないのですか?実行時にそれがどうして起こるのですか? –

+0

@KirkWoll私はラムダ式をメタデータとして使用しています。文脈では、表現が生成され、argumは、コード内の別のポイントでユーザに表示したいものと異なる場合があります。小さなプロジェクト全体は、エラーを表示するためにマジック文字列を使用しない引数検証ライブラリです。 –

答えて

8

それは、迅速かつ汚いですが、あなたは.NET 4.0を使用していると仮定すると次のようなを作成することができます。

次のように
public class PredicateRewriter 
{ 
    public static Expression<Predicate<T>> Rewrite<T>(Expression<Predicate<T>> exp, string newParamName) 
    { 
     var param = Expression.Parameter(exp.Parameters[0].Type, newParamName); 
     var newExpression = new PredicateRewriterVisitor(param).Visit(exp); 

     return (Expression<Predicate<T>>) newExpression; 
    } 

    private class PredicateRewriterVisitor : ExpressionVisitor 
    { 
     private readonly ParameterExpression _parameterExpression; 

     public PredicateRewriterVisitor(ParameterExpression parameterExpression) 
     { 
      _parameterExpression = parameterExpression; 
     } 

     protected override Expression VisitParameter(ParameterExpression node) 
     { 
      return _parameterExpression; 
     } 
    } 
} 

そして、それを使用します。式はとても不変です

var newExp = PredicateRewriter.Rewrite(exp, "b"); 
newExp.ToString(); // returns "b => (b.First() == 0)" in your case 
+0

ありがとうございます、魅力のように動作します。 –

+0

しかし、すべてのパラメータを "b"に変更しようとしています。 "a"だけを "b"に変更したい場合は、私の解決策を見てください。 – Krizz

0

通常、私はJetbrains Resharperなどのリファクタリングツールを使用します。これにはリファクタリング、名前変更という機能があり、文字列置換と変数名の変更の違いを知ることができます。私はVisual Studio自体の中からそのような機能がないことを知っています。

// Create a parameter which passes the object 
    ParameterExpression param = Expression.Parameter(typeof(E), "x"); //x replaces a=> 

    // Create body of lambda expression 
    Expression body = Expression.PropertyOrField(param, fieldname); 

    // Create lambda function 
    Expression<Func<E, string>> exp = Expression.Lambda<Func<E, string>>(body, param); 

    // Compile it so we can use it 
    Func<E, string> orderFunc = exp.Compile(); 

、パラメータを変更するには:あなたは、このような(c# List<string> to Lambda Expression with starter example: Refactor to handle the Listからコピーされた)次のようなコードを使用することができますhttp://www.jetbrains.com/resharper/

あなたはしかし、動的な表現を構築するを参照し、パラメータを変更したい場合は、 「X」から「Y」に、私たちは次のことを行うことができます:

var newExpression = ReplaceFirstParameterName(exp, "y"); 

    private Expression<Func<E, string>>(Expression<Func<E,string>> exp, string newParamName) 
    { 
     var cloneParam = Expression.Parameter(exp.Parameters[0].Type, newParamName); 
     var body = exp.Body; 
     var newExp = Expression.Lambda<Func<string, string>>(body, cloneParam); 
     return newExp; 
    } 
+0

私は実行時に実行する必要があることを指定していません。 –

+0

(+1)のように見えますが、この例ではcrsの新しい式が作成されています。 –

+0

上記のコードはうまくいきますが、指定した文字列を式に戻してからパラメータ名を変更することで、実際に指定したことはできません。ここでは、文字列からのラムダ式パーサーがない方法についての長い議論があります。主に、(正しくディスカッションを解釈すると)変数スコープの競合に関する問題がある可能性があります。http://www.tech-archive.net/Archive /DotNet/microsoft.public.dotnet.languages.csharp/2007-05/msg04019.htmlソースが特に文字列でない場合は、Expressionオブジェクトのパラメータを変更できます。 – JNadal

5

、そのため、あなたは新しいツリーを構築する必要があるだろう 、それらを変更することはできません。 .NET 4.0では

は、大幅にあなたを助けることができるクラスがあり、あなたが行うことができますExpressionVisitor

を参照してください。

public class Renamer : ExpressionVisitor 
{ 
    public Expression Rename(Expression expression) 
    { 
     return Visit(expression); 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     if (node.Name == "a") 
      return Expression.Parameter(node.Type, "something_else"); 
     else 
      return node; 
    } 
} 

、その後、new Renamer().Rename(exp).ToString()は、あなたが期待するものを保持する必要があります。

+0

あなたは他の人がすべてのパラメータの名前を変更するのは間違いありませんが、あなたの提案は私のためにすぐにはうまくいかなかった:おそらくVisitParameterがオーバーライドしていないので? –

+0

はい、修正されました。指摘してくれてありがとう。 – Krizz

+0

私はすでに前に+1したので、もう一度増やせません。申し訳ありません –

関連する問題