Pregunta

Estoy intentando usar Lambda Expressions en un proyecto para asignarlo a una API de consulta de terceros. Por lo tanto, estoy analizando el árbol de Expresión a mano.

Si paso una expresión lambda como:

p => p.Title == "title"

todo funciona.

Sin embargo, si mi expresión lambda se ve así:

p => p.Title == myaspdropdown.SelectedValue

Al usar el depurador .NET, no veo el valor real de esa función. En cambio veo algo como:

p => p.Title = (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)

¿Qué da? Y cuando intento tomar el lado derecho de la expresión como una cadena, obtengo (value (ASP.usercontrols_myaspusercontrol_ascx) .myaspdropdown.SelectedValue) en lugar del valor real. ¿Cómo obtengo el valor real?

¿Fue útil?

Solución

Recuerda que cuando tratas con la expresión lambda como un árbol de expresiones, no tienes código ejecutable. Más bien, tiene un árbol de elementos de expresión, que conforman la expresión que escribió.

Charlie Calvert tiene una buena publicación que discute esto en detalle. Se incluye un ejemplo del uso de un visualizador de expresiones para la depuración de expresiones.

En su caso, para obtener el valor del lado derecho de la expresión de igualdad, deberá crear una nueva expresión lambda, compilarla y luego invocarla.

He pirateado juntos un ejemplo rápido de esto: espero que ofrezca lo que necesitas.

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

Otros consejos

Para obtener el valor real, debes aplicar la lógica del árbol de expresiones a cualquier contexto que tengas.

El punto principal de los árboles de expresión es que representan la lógica como datos en lugar de evaluar la expresión. Tendrá que averiguar qué significa realmente la expresión lambda. Eso puede significar evaluar algunas partes de la misma en función de los datos locales; tendrá que decidirlo usted mismo. Los árboles de expresión son muy poderosos, pero no es una cuestión simple analizarlos y usarlos. (Pregunte a cualquiera que haya escrito un proveedor de LINQ ... Frans Bouma ha lamentado las dificultades varias veces).

Solo he estado luchando con exactamente el mismo problema, gracias Bevan. En una extensión, el siguiente es un patrón genérico que puede usar para extraer el valor (usando esto en mi motor 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();
    }
}

No estoy seguro de entender. ¿Dónde estás " viendo " ¿ese? ¿Es eso en tiempo de diseño o tiempo de ejecución? Las expresiones Lambda se pueden considerar esencialmente como delegados anónimos y operarán con ejecución diferida. Por lo tanto, no debe esperar ver el valor asignado hasta después de que la ejecución haya superado esa línea, obviamente.
No creo que realmente sea a eso a lo que te refieres ... si clarificas un poco la pregunta, quizás pueda ayudarte :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top