Lambda 表达式树解析

发布于 2024-07-08 02:51:03 字数 602 浏览 5 评论 0原文

我正在尝试在项目中使用 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) 而不是实际值。 如何获得实际值?

I am trying to use Lambda Expressions in a project to map to a third party query API. So, I'm parsing the Expression tree by hand.

If I pass in a lambda expression like:

p => p.Title == "title"

everything works.

However, if my lambda expression looks like:

p => p.Title == myaspdropdown.SelectedValue

Using the .NET debugger, I don't see the actual value of that funciton. Instead I see something like:

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

What gives? And when I try to grab the right side of the expression as a string, I get (value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue) instead of the actual value. How do I get the actual value?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萧瑟寒风 2024-07-15 02:51:07

请记住,当您将 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; }
}

Remember that when you're dealing with the lambda expression as an expression tree, you don't have executable code. Rather you have a tree of expression elements, that make up the expression you wrote.

Charlie Calvert has a good post that discusses this in detail. Included is an example of using an expression visualiser for debugging expressions.

In your case, to get the value of the righthand side of the equality expression, you'll need to create a new lambda expression, compile it and then invoke it.

I've hacked together a quick example of this - hope it delivers what you need.

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; }
}
泪意 2024-07-15 02:51:07

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

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

To get the actual value, you need to apply the logic of the expression tree to whatever context you've got.

The whole point of expression trees is that they represent the logic as data rather than evaluating the expression. You'll need to work out what the lambda expression truly means. That may mean evaluating some parts of it against local data - you'll need to decide that for yourself. Expression trees are very powerful, but it's not a simple matter to parse and use them. (Ask anyone who's written a LINQ provider... Frans Bouma has bemoaned the difficulties several times.)

沫雨熙 2024-07-15 02:51:07

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

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

Just been struggling with exactly the same issue, thanks Bevan. On an extension, the following is a generic pattern you can use to extract the value (using this in my query engine).

    [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();
    }
}
无边思念无边月 2024-07-15 02:51:07

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

I'm not sure I understand. Where are you "seeing" that? Is that at design-time or run-time? Lambda expressions can be thought of essentially as anonymous delegates, and will operate with deferred execution. So you shouldn't expect to see the value assigned until after execution has passed that line, obviously.
I don't think that's really what you mean though... if you clarify the question a bit maybe I can help :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文