从 MemberExpression 中获取对象?
那么,假设我在 C# 中有以下表达式:
Expression<Func<string>> expr = () => foo.Bar;
如何提取对 foo 的引用?
So, lets say I have the following expression in C#:
Expression<Func<string>> expr = () => foo.Bar;
How do I pull out a reference to foo?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
情况 1:根对象是实例成员
...相当于以下表达式树:
此中的唯一位置您实际获取对象引用的表达式树来自
ConstantExpression
:它允许您获取对this
的引用。获取此树中任何对象引用的基本思想如下:沿着
.Expression
轴下降到表达式树中,直到到达ConstantExpression
节点。获取该节点的
.Value
属性。这是根对象引用(即上面示例中的this
)。使用反射和表达式树中的
MemberInfo
节点,获取对象引用并返回表达式树“向上”。下面的一些代码演示了这一点:
情况 2:根对象是静态类成员
...导致不同的表达式树。请注意左下角的空引用:
在这里,您无法通过等待
ConstantExpression
来停止“下降”阶段。相反,当到达空引用时,您将停止下降。接下来,您检索根对象引用,如下所示:从那里开始的“上升”阶段与之前相同。
当然还有更多的情况(例如命名参数作为根对象),但我希望到目前为止,我已经了解了基本的想法,所以我将在这里中断。
Case 1: The root object is an instance member
... is equivalent to the following expression tree:
The only place in this expression tree where you actually get an object reference is from the
ConstantExpression
: it allows you to get a reference tothis
. The basic idea to get any object reference in this tree is thus as follows:Descend into the expression tree along the
.Expression
axes until you reach aConstantExpression
node.Grab that node's
.Value
property. This is the root object reference (ie.this
in the above example).Using reflection and the
MemberInfo
nodes from the expression tree, get object references and work your way back "up" the expression tree.Here's some code that demonstrates this:
Case 2: The root object is a static class member
... results in a different expression tree. Note to the null reference at the lower left:
Here, you cannot stop the "descend" phase by waiting for a
ConstantExpression
. Instead, you stop descending when you reach a null reference. Next, you retrieve the root object reference as follows:The "ascend" phase from there onwards is the same as before.
There are certainly more cases (such as named parameters as the root object), but I hope that by now, I've got the basic idea across, so I'll cut off here.
有一个更简单的解决方案:
There is a simpler solution:
谢谢,staks - 你的例子对我帮助很大!所以我想对第一种情况做出一些补充:
要从方法中提取值,应该将 code: 替换
为 code:
这样就可以从表达式中提取值,例如:
Thanks, staks - your example helped me a lot! So i'd like to contribute with some addition to the first case:
To extract values from methods, one should replace code:
with code:
that way one could extract values from expressions like:
这是我在单元测试中使用的:
This is what I use in unit tests:
这里实际上有两件独立的事情要做:
一旦我们能做到1,那么2就变得相对简单了。
请注意,这是必要的原因是,为了获取该成员的所有者,需要获取该成员的所有者的所有者(询问其成员之一的值)。
(另请注意:成员所有者的所有者可以是隐藏的闭包实例,问题中给出的示例就是这种情况。
() => foo.Bar
实际上是 < code>() =>closure.foo.Bar.)可以像这样评估表达式链。请注意,它是递归的,因为我们不知道链有多长。 (只要有成员,您就需要每个父级的值来评估该父级的成员之一。)这也可以扩展以支持其他类型的表达式。
现在使用上面的内容,我们可以执行以下操作来获取成员的所有者:
There are really two separate things to do here:
Once we can do 1, then 2 becomes relatively straightforward.
Note the reason this is necessary is that in order to get the owner of the member requires getting the owner of the owner of the member (to ask it for the value of one of its members).
(Also note: the owner of the owner of the member can be a hidden closure instance, which would be the case in the example given in the question.
() => foo.Bar
is really() => closure.foo.Bar
.)Evaluating an expression chain can be done something like this. Note that it's recursive, since we don't know how long the chain is. (As long as there are members, you need the value of each parent to evaluate one of that parent's members.) This could also be expanded to support other kinds of expression.
Now using the above, we can just do the following to get the owner of the member: