Вопрос

Я пытаюсь использовать лямбда-выражения в проекте для сопоставления стороннему API запросов. Итак, я вручную разбираю дерево выражений.

Если я передам лямбда-выражение вроде:

p => p.Title == "title"

все работает.

Однако, если мое лямбда-выражение выглядит так:

p => p.Title == myaspdropdown.SelectedValue

Используя отладчик .NET, я не вижу действительного значения этой функции. Вместо этого я вижу что-то вроде:

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

Что дает? И когда я пытаюсь получить правую часть выражения в виде строки, вместо фактического значения я получаю (значение (ASP.usercontrols_myaspusercontrol_ascx) .myaspdropdown.SelectedValue) . Как узнать фактическое значение?

Это было полезно?

Решение

Помните, что когда вы имеете дело с лямбда-выражением в виде дерева выражений, у вас нет исполняемого кода. Скорее у вас есть дерево элементов выражения, которые составляют написанное вами выражение.

Чарли Калверт имеет хороший пост что обсуждается это подробно. Включен пример использования визуализатора выражений для отладки выражений.

В вашем случае, чтобы получить значение правой части выражения равенства, вам нужно создать новое лямбда-выражение, скомпилировать его и затем вызвать.

Я собрал краткий пример этого - надеюсь, он даст вам то, что вам нужно.

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

Другие советы

Чтобы получить действительное значение, вам нужно применить логику дерева выражений к любому контексту, который у вас есть.

Весь смысл деревьев выражений состоит в том, что они представляют логику как данные, а не как выражение выражения. Вам нужно разобраться, что на самом деле означает лямбда-выражение. Это может означать сравнение некоторых его частей с локальными данными - вам нужно решить это для себя. Деревья выражений очень мощные, но их непросто проанализировать и использовать. (Спросите любого, кто написал провайдера LINQ ... Франс Боума несколько раз оплакивал трудности.)

Просто боролся с точно такой же проблемой, спасибо Беван. В расширении ниже приведен общий шаблон, который можно использовать для извлечения значения (используя это в моей системе запросов).

    [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();
    }
}

Я не уверен, что понимаю. Где ты "видишь"? тот? Это во время разработки или во время выполнения? Лямбда-выражения можно рассматривать по существу как анонимные делегаты, и они будут работать с отложенным выполнением. Таким образом, вы не должны ожидать увидеть назначенное значение до тех пор, пока выполнение не пройдет эту строку, очевидно.
Я не думаю, что это действительно то, что вы имеете в виду ... если вы немного проясните вопрос, может быть, я могу помочь:)

scroll top