Lambda Expression árvore de análise
-
04-07-2019 - |
Pergunta
Eu estou tentando usar expressões lambda em um projeto para mapear para uma consulta de API de terceiros. Então, eu estou analisando a árvore de expressão à mão.
Se eu passar em uma expressão lambda como:
p => p.Title == "title"
tudo funciona.
No entanto, se os meus lambda expressão se parece com:
p => p.Title == myaspdropdown.SelectedValue
Usando o depurador .NET, eu não vejo o valor real do que funciton. Em vez disso eu ver algo como:
p => p.Title = (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)
O que dá? E quando eu tentar agarrar o lado direito da expressão como uma string, recebo (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)
em vez do valor real. Como posso obter o valor real?
Solução
Lembre-se que quando você está lidando com a expressão lambda como uma árvore de expressão, você não tem código executável. Em vez disso você tem uma árvore de elementos de expressão, que compõem a expressão que você escreveu.
Charlie Calvert tem um bom post que discute isso em detalhes. Incluído é um exemplo do uso de um visualizador expressão para depurar expressões.
No seu caso, para obter o valor do lado direito da expressão de igualdade, você precisa criar uma nova expressão lambda, compilá-lo e, em seguida, invocá-lo.
Eu tenho cortado juntos um exemplo rápido deste -. Esperança que oferece o que você precisa
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; }
}
Outras dicas
Para obter o valor real, é preciso aplicar a lógica da árvore de expressão para qualquer contexto que você tem.
O ponto inteiro de árvores de expressão é que eles representam o lógica como dados em vez de avaliar a expressão. Você precisa descobrir o que a expressão lambda realmente significa. Isso pode significar avaliar algumas partes dele em relação aos dados locais - você precisa decidir isso por si mesmo. Árvores de expressão são muito poderoso, mas não é uma simples questão de analisar e usá-los. (Pergunte a qualquer um que escreveu um provedor LINQ ... Frans Bouma tem lamentou as dificuldades várias vezes.)
Apenas sido lutando com exatamente o mesmo problema, graças Bevan. Em uma extensão, o seguinte é um padrão genérico que você pode usar para extrair o valor (usando isso no meu mecanismo de consulta).
[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();
}
}
Eu não tenho certeza eu entendo. Onde você está "vendo" isso? É que em tempo de design ou tempo de execução? As expressões lambda pode ser pensado essencialmente como delegados anônimos, e irá operar com a execução diferida. Então você não deve esperar para ver o valor atribuído até que após a execução tenha passado essa linha, obviamente.
Eu não acho que isso é realmente o que você quer dizer embora ... se esclarecer a questão um pouco talvez eu possa ajudar:)