2011-12-16 10 views
11

Diciamo che ho un'espressione come questa:Cambiare nome del parametro in un LambdaExpression solo per la visualizzazione

Expression<Predicate<T>> exp 

Se assegno la seguente espressione:

a => a.First() != 0 

e poi chiamo exp.ToString() otterrò esattamente l'espressione che ho passato, è perfettamente buona, ma, supponiamo di voler cambiare il nome che usiamo per "a" con qualcos'altro, come possiamo fare? La sostituzione delle stringhe non funzionerebbe in tutti i casi (funziona nell'esempio sopra, ma cosa succede se il parametro è stato chiamato 'i' per esempio?) È possibile avere solo la sostituzione del nome parametro, il tempo di esecuzione, senza influire sul espressione semantica?

UPDATE Il @PhilKlein funziona perfettamente, ma richiede quadro 4. Ma se abbiamo bisogno di indirizzare il Framework 3.5 si può utilizzare una classe ExpressionVisitor da Matt Warren, semplicemente modifing da protetto al pubblico il metodo di visita.

+0

Non capisco perché si desidera generare una stringa che rappresenta l'espressione in cui non corrisponde esattamente all'espressione. Perchè vuoi fare questo? Perché * non * si vuole refactoring il codice - perché deve accadere in fase di runtime? –

+0

@KirkWoll Sto usando l'espressione lambda come metadata. Nel contesto in cui viene generata l'espressione, l'argumet può essere diverso da quello che voglio mostrare all'utente in un altro punto del codice. L'intero piccolo progetto è una libreria di convalida degli argomenti che non usa la stringa magica per visualizzare gli errori. –

risposta

8

e 'veloce e sporco, ma supponendo che si sta utilizzando .NET 4.0 è possibile creare il seguente:

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; 
     } 
    } 
} 

e quindi utilizzarlo come segue:

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

Grazie, funziona come un fascino. –

+0

Ma cambierà tutti i parametri in "b". Se si desidera che solo "a" sia cambiato in "b", vedere la mia soluzione. – Krizz

0

In genere, utilizzerei uno strumento di refactoring, ad esempio Jethares Resharper per farlo. Ha una funzione "Refactor, Rename" che ti permette di fare proprio questo, e conosce la differenza tra una stringa sostituita e una variabile rinomina. Non conosco tali funzionalità all'interno di Visual Studio stesso. http://www.jetbrains.com/resharper/

Se lei si riferisce alla costruzione di un'espressione dinamica, però, e si desidera modificare il parametro, è possibile utilizzare il codice come il seguente (copiato da: c# List<string> to Lambda Expression with starter example: Refactor to handle the List)

// 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(); 

E per modificare il parametro da "x" a "y", potremmo effettuare le seguenti operazioni:

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

Mi manca specificare che deve essere fatto runtime. –

+0

Sembra la strada da percorrere (+1) ma l'esempio crea una nuova espressione da s cratch, per contrario la mia è già attiva. –

+0

Il codice sopra funziona, quindi, tuttavia non esegue realmente ciò che è stato specificato, ovvero la conversione della stringa in un'espressione e quindi la modifica del nome del parametro. C'è una discussione piuttosto lunga qui su come non c'è un parser di espressioni lambda da una stringa, principalmente perché potrebbero esserci problemi con (se ho interpretato correttamente la discussione) conflitti di scope variabili: http://www.tech-archive.net/Archive /DotNet/microsoft.public.dotnet.languages.csharp/2007-05/msg04019.html Se la fonte non è specificamente una stringa, è possibile modificare i parametri dell'oggetto Expression. – JNadal

5

espressioni sono immutabili così, di conseguenza, non è possibile modificarli, si avrebbe bisogno di costruire nuovo albero.

In .NET 4.0, c'è una classe che può aiutare in modo significativo, vedere ExpressionVisitor

si può fare:

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; 
    } 
} 

e poi, new Renamer().Rename(exp).ToString() dovrebbe tenere ciò che vi aspettate.

+0

hai ragione l'altro rinominare tutti i parametri, ma la tua proposta non ha funzionato fuori dagli schemi per me: forse perché VisitParameter non ha la precedenza? –

+0

sì, corretto. Grazie per la segnalazione. – Krizz

+0

Ho già votato +1 prima, quindi non posso aumentare nuovamente, mi spiace, –

Problemi correlati