C# Lambda 表达式树解析
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/238413/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Lambda Expression Tree Parsing
提问by Keith Fitzgerald
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.
我正在尝试在项目中使用 Lambda 表达式来映射到第三方查询 API。所以,我正在手动解析表达式树。
If I pass in a lambda expression like:
如果我传入一个 lambda 表达式,例如:
p => p.Title == "title"
everything works.
一切正常。
However, if my lambda expression looks like:
但是,如果我的 lambda 表达式如下所示:
p => p.Title == myaspdropdown.SelectedValue
Using the .NET debugger, I don't see the actual value of that funciton. Instead I see something like:
使用 .NET 调试器时,我看不到该函数的实际值。相反,我看到的是:
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?
是什么赋予了?当我尝试将表达式的右侧作为字符串抓取时,我得到的(value(ASP.usercontrols_myaspusercontrol_ascx).myaspdropdown.SelectedValue)
不是实际值。我如何获得实际价值?
采纳答案by Bevan
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.
请记住,当您将 lambda 表达式作为表达式树处理时,您没有可执行代码。相反,您有一个表达式元素树,它们构成了您编写的表达式。
Charlie Calvert has a good postthat discusses this in detail. Included is an example of using an expression visualiser for debugging expressions.
Charlie Calvert 有一篇很好的帖子详细讨论了这一点。包括使用表达式可视化器调试表达式的示例。
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.
在您的情况下,要获取等式表达式右侧的值,您需要创建一个新的 lambda 表达式,编译它然后调用它。
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; }
}
回答by Grank
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 :)
我不确定我是否理解。你在哪里“看到”那个?那是在设计时还是运行时?Lambda 表达式本质上可以被认为是匿名委托,并且将使用延迟执行进行操作。因此,很明显,在执行通过该行之前,您不应期望看到分配的值。
我不认为这真的是你的意思......如果你澄清一下这个问题也许我可以帮忙:)
回答by Jon Skeet
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 logicas 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.)
表达式树的全部意义在于它们将逻辑表示为数据而不是计算表达式。您需要弄清楚 lambda 表达式的真正含义。这可能意味着根据本地数据评估其中的某些部分 - 您需要自己决定。表达式树非常强大,但是解析和使用它们并不是一件简单的事情。(问问任何写过 LINQ 提供程序的人……Frans Bouma 曾多次哀叹这些困难。)
回答by squirrel
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();
}
}