【问题标题】:Lambda Expression Tree ParsingLambda 表达式树解析
【发布时间】:2010-09-19 07:11:54
【问题描述】:

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

【问题讨论】:

  • 我认为问题是(而且我不是表达式专家,所以这不是答案)是表达式不是 lambda;它描述了您希望检索的数据。它没有被执行,它被解释了。
  • 这意味着该值不会在运行时替换您的表达式,而是在编译时永久设置。为了获取值,解释 lambda 的代码必须了解用户控件的概念以及如何提取它
  • 除非解释表达式的代码可以访问您的控件并且被编码为执行此操作,否则这是不可能的。如果代码有一个重载或另一个执行相同操作但获取实际值的方法,您可以使用它和一个 lambda 在运行时检索该值。

标签: c# lambda expression-trees


【解决方案1】:

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

Charlie Calvert 的a good post 对此进行了详细讨论。包括使用表达式可视化工具调试表达式的示例。

在您的情况下,要获取等式表达式右侧的值,您需要创建一个新的 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; }
}

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    【解决方案3】:

    一直在努力解决完全相同的问题,谢谢 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();
        }
    }
    

    【讨论】:

    • 与其使用你的反射调用 InvokeGeneric,我会做的是Expression&lt;Func&lt;object&gt;&gt;(Expression.Convert(expression, typeof(object))).Compile()
    【解决方案4】:

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

    【讨论】:

    • 更新问题。它在调试器中[以及当我尝试抓住表达式的右侧时]
    • @Grank:Lambda 表达式可以转换为表达式树或委托。听起来您正在考虑转换为委托。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多