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

如果我传入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表达式作为表达式树处理时,您没有可执行代码。相反,你有一个表达元素树,构成你写的表达式。

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

其他提示

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

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

刚刚在同一个问题上苦苦挣扎,谢谢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();
    }
}

我不确定我理解。你在哪里“看到”那?那是在设计时还是在运行时? Lambda表达式基本上可以被认为是匿名委托,并且将使用延迟执行。所以你不应该期望在执行过去之前看到分配的值,显然。点击 我不认为这真的是你的意思......如果你澄清一下这个问题,我可以提供帮助:)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top