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?

Foi útil?

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:)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top