2016-04-29 32 views
5

In una delle mie librerie, Ho codice che restituisce un MethodInfo da un'espressione:Perché i differenti versioni di .net (o il compilatore) generano diversi alberi di espressione per la stessa espressione

public MethodInfo GetMethod(Expression expression) 
{ 
    var lambdaExpression = (LambdaExpression)expression; 
    var unaryExpression = (UnaryExpression)lambdaExpression.Body; 
    var methodCallExpression = (MethodCallExpression)unaryExpression.Operand; 
    var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last(); 
    return (MethodInfo)methodInfoExpression.Value; 
} 

Ho avuto un serie di funzioni di supporto per abilitare le chiamate come la seguente:

public MethodInfo Func<T, R, A1>(Expression<Func<T, Func<A1, R>>> expression) 
{ 
    return GetMethod(expression); 
} 

Ciò consentirebbe la seguente sintassi:

var methodInfo = Func<TestClass, bool, string>(x => x.AnInstanceMethodThatTakesAStringAndReturnsABool); 

Questo ha funzionato benissimo, fino a quando non ho aggiornato la libreria su .Net 4.6.1 e l'ultimo compilatore C#.

Nella versione precedente di .NET, l'espressione sarebbe della forma:

{x => Convert(CreateDelegate(System.Func`2[System.String, System.Boolean], x, Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String)))} 

Da qui il mio codice sarà per la methodInfoExpression come ultimo argomento del methodCallExpression.

Ora, in .Net 4.6.1 (ultima compilatore C#), il compilatore sembra essere la produzione di espressione di una forma diversa:

{x => Convert(Boolean AnInstanceMethodThatTakesAStringAndReturnsABool(System.String).CreateDelegate(System.Func`2[System.String, System.Boolean], x))} 

mie pause di codici attuali, perché l'ultimo argomento non è un ConstantExpression . Guardando la cosa - soluzione semplice, basta cambiare a

var methodInfoExpression = (ConstantExpression)methodCallExpression.Object; 

Ovviamente, la funzione GetMethod è piuttosto fragile e soggetto a modifiche al modo in cui il compilatore genera espressioni. Sono curioso di sapere la ragione del cambiamento e di come posso rifattare GetMethod in modo che sia più resistente all'albero delle espressioni generato dal compilatore.

+1

Si dovrebbe davvero pubblicare il codice di esempio che compila quando si fornisce un esempio. E se vuoi aiutare a scrivere il metodo in modo più efficace, dovresti effettivamente descrivere ciò che deve fare, piuttosto che mostrare solo la versione non funzionante di esso. – Servy

risposta

4

Sono curioso di sapere il motivo per il cambiamento

Come di .NET 4.5 ci sono due modi di fare un delegato MethodInfo: Metodo

  1. Un'istanza su MethodInfo e
  2. Delegate.CreateDelegate metodo statico

Sembra che Microsoft abbia deciso di passare dall'uso del # 2 all'utilizzo del # 1, per qualsiasi motivo (probabilmente è più efficiente).

come potrei refactoring GetMethod in modo che sia più resiliente per l'albero di espressioni generato dal compilatore?

È possibile utilizzare expression tree visitor e cercare le informazioni sul metodo in questo modo.

+0

Molto utile. Grazie! –