Analisi dell'albero delle espressioni lambda
-
04-07-2019 - |
Domanda
Sto cercando di utilizzare Lambda Expressions in un progetto per mappare un'API di query di terze parti. Quindi, sto analizzando l'albero delle espressioni a mano.
Se passo un'espressione lambda come:
p => p.Title == "title"
tutto funziona.
Tuttavia, se la mia espressione lambda è simile a:
p => p.Title == myaspdropdown.SelectedValue
Usando il debugger .NET, non vedo il valore effettivo di quella funzione. Invece vedo qualcosa di simile:
p => p.Title = (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)
Cosa dà? E quando provo ad afferrare il lato destro dell'espressione come stringa, ottengo (value (ASP.usercontrols_myaspusercontrol_ascx) .myaspdropdown.SelectedValue)
invece del valore effettivo. Come posso ottenere il valore effettivo?
Soluzione
Ricorda che quando hai a che fare con l'espressione lambda come albero delle espressioni, non hai un codice eseguibile. Piuttosto hai un albero di elementi espressivi, che compongono l'espressione che hai scritto.
Charlie Calvert ha un buon post che ne discute in dettaglio. È incluso un esempio dell'utilizzo di un visualizzatore di espressioni per il debug delle espressioni.
Nel tuo caso, per ottenere il valore del lato destro dell'espressione di uguaglianza, dovrai creare una nuova espressione lambda, compilarla e quindi invocarla.
Ho hackerato insieme un rapido esempio di questo - spero che offra ciò di cui hai bisogno.
public class Class1
{
public string Selection { get; set; }
public void Sample()
{
Selection = "Example";
Example<Book, bool>(p => p.Title == Selection);
}
public void Example<T,TResult>(Expression<Func<T,TResult>> exp)
{
BinaryExpression equality = (BinaryExpression)exp.Body;
Debug.Assert(equality.NodeType == ExpressionType.Equal);
// Note that you need to know the type of the rhs of the equality
var accessorExpression = Expression.Lambda<Func<string>>(equality.Right);
Func<string> accessor = accessorExpression.Compile();
var value = accessor();
Debug.Assert(value == Selection);
}
}
public class Book
{
public string Title { get; set; }
}
Altri suggerimenti
Per ottenere il valore effettivo, è necessario applicare la logica dell'albero delle espressioni a qualsiasi contesto si disponga.
L'intero albero delle espressioni è che rappresentano la logica come dati anziché valutare l'espressione. Dovrai capire cosa significa veramente l'espressione lambda. Ciò può significare valutare alcune parti di esso in base ai dati locali: dovrai decidere tu stesso. Gli alberi delle espressioni sono molto potenti, ma non è semplice analizzarli e usarli. (Chiedi a chiunque abbia scritto un provider LINQ ... Frans Bouma si è lamentato più volte delle difficoltà.)
Ho appena avuto problemi con lo stesso problema, grazie Bevan. Su un'estensione, il seguente è un modello generico che puoi usare per estrarre il valore (usando questo nel mio motore di query).
[TestFixture]
public class TestClass
{
[Test]
public void TEst()
{
var user = new User {Id = 123};
var idToSearch = user.Id;
var query = Creator.CreateQuery<User>()
.Where(x => x.Id == idToSearch);
}
}
public class Query<T>
{
public Query<T> Where(Expression<Func<T, object>> filter)
{
var rightValue = GenericHelper.GetVariableValue(((BinaryExpression)((UnaryExpression)filter.Body).Operand).Right.Type, ((BinaryExpression)((UnaryExpression)filter.Body).Operand).Right);
Console.WriteLine(rightValue);
return this;
}
}
internal class GenericHelper
{
internal static object GetVariableValue(Type variableType, Expression expression)
{
var targetMethodInfo = typeof(InvokeGeneric).GetMethod("GetVariableValue");
var genericTargetCall = targetMethodInfo.MakeGenericMethod(variableType);
return genericTargetCall.Invoke(new InvokeGeneric(), new[] { expression });
}
}
internal class InvokeGeneric
{
public T GetVariableValue<T>(Expression expression) where T : class
{
var accessorExpression = Expression.Lambda<Func<T>>(expression);
var accessor = accessorExpression.Compile();
return accessor();
}
}
Non sono sicuro di aver capito. Dove stai vedendo " quello? È in fase di progettazione o in fase di esecuzione? Le espressioni lambda possono essere pensate essenzialmente come delegati anonimi e funzioneranno con un'esecuzione differita. Quindi non dovresti aspettarti di vedere il valore assegnato fino a dopo che l'esecuzione ha superato quella linea, ovviamente.
Non penso che sia davvero quello che vuoi dire ... se chiarisci un po 'la domanda forse posso aiutarti :)