16

我正在尝试在项目中使用 Lambda 表达式来映射到第三方查询 API。所以,我正在手动解析表达式树。

如果我传入一个 lambda 表达式,例如:

p => p.Title == "title"

一切正常。

但是,如果我的 lambda 表达式看起来像:

p => p.Title == myaspdropdown.SelectedValue

使用 .NET 调试器,我看不到该功能的实际价值。相反,我看到了类似的东西:

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

是什么赋予了?当我尝试将表达式的右侧作为字符串抓取时,我得到(value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)的不是实际值。我如何获得实际价值?

4

4 回答 4

21

请记住,当您将 lambda 表达式作为表达式树处理时,您没有可执行代码。相反,您有一个表达式元素树,它们构成了您编写的表达式。

Charlie Calvert 有一篇很好的帖子详细讨论了这一点。包括使用表达式可视化器调试表达式的示例。

在您的情况下,要获取等式表达式右侧的值,您需要创建一个新的 lambda 表达式,编译它然后调用它。

我已经编写了一个简单的示例 - 希望它能够满足您的需求。

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; }
}
于 2008-10-27T08:53:00.873 回答
1

要获得实际值,您需要将表达式树的逻辑应用于您拥有的任何上下文。

表达式树的全部意义在于它们将逻辑表示为数据,而不是评估表达式。您需要弄清楚 lambda 表达式的真正含义。这可能意味着根据本地数据评估其中的某些部分 - 您需要自己决定。表达式树非常强大,但是解析和使用它们并不是一件简单的事情。(询问任何编写过 LINQ 提供程序的人...... Frans Bouma 曾多次哀叹这些困难。)

于 2008-10-26T19:46:31.007 回答
0

一直在努力解决完全相同的问题,谢谢贝文。在扩展上,以下是可用于提取值的通用模式(在我的查询引擎中使用它)。

    [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();
    }
}
于 2010-09-16T12:20:28.627 回答
-1

我不确定我是否理解。你在哪里“看到”那个?那是在设计时还是运行时?Lambda 表达式本质上可以被认为是匿名委托,并且将在延迟执行的情况下进行操作。因此,显然,在执行通过该行之前,您不应该期望看到分配的值。
我不认为这真的是你的意思......如果你澄清一下这个问题也许我可以帮助:)

于 2008-10-26T18:42:45.223 回答