Bri*_*sio 38 c# lambda expression-trees
所以,假设我在C#中有以下表达式:
Expression<Func<string>> expr = () => foo.Bar;
Run Code Online (Sandbox Code Playgroud)
如何提取对foo的引用?
sta*_*ica 48
我有同样的问题,但有点复杂,Darin Dimitrov的回答给了我一个良好的开端.我会在这里发布我的结果,尽管这是一个"老"的问题.
this.textBox.Text // where 'this' has type 'Form'
Run Code Online (Sandbox Code Playgroud)
...等同于以下表达式树:
. +====================+
. | MemberExpression |
. +====================+
# | |
# .Expression | | .Member
# v v
. +------------------+ +------------+
. | MemberExpression | | MemberInfo |
. +------------------+ +------------+
# | | .Name = "Text"
# .Expression | | .Member .MemberType = Property
# v v
. +--------------------+ +------------+
. | ConstantExpression | | MemberInfo |
. +--------------------+ +------------+
# .Value = this .Name = "textBox"
# .Type = typeof(Form) .MemberType = Field
Run Code Online (Sandbox Code Playgroud)
实际获得对象引用的表达式树中唯一的位置是ConstantExpression
:它允许您获取对它的引用this
.因此,在此树中获取任何对象引用的基本思想如下:
沿着.Expression
轴下降到表达式树,直到到达ConstantExpression
节点.
抓住该节点的.Value
属性.这是根对象引用(即this
在上面的示例中).
使用反射和MemberInfo
表达式树中的节点,获取对象引用并以"向上"方式返回表达式树.
这里有一些代码可以证明这一点:
Expression expr = ...; // <-- initially set to the expression tree's root
var memberInfos = new Stack<MemberInfo>();
// "descend" toward's the root object reference:
while (expr is MemberExpression)
{
var memberExpr = expr as MemberExpression;
memberInfos.Push(memberExpr.Member);
expr = memberExpr.Expression
}
// fetch the root object reference:
var constExpr = expr as ConstantExpression;
var objReference = constExpr.Value;
// "ascend" back whence we came from and resolve object references along the way:
while (memberInfos.Count > 0) // or some other break condition
{
var mi = memberInfos.Pop();
if (mi.MemberType == MemberTypes.Property)
{
objReference = objReference.GetType()
.GetProperty(mi.Name)
.GetValue(objReference, null);
}
else if (mi.MemberType == MemberTypes.Field)
{
objReference = objReference.GetType()
.GetField(mi.Name)
.GetValue(objReference);
}
}
Run Code Online (Sandbox Code Playgroud)
Form.textBox.Text // where 'textBox' is a static member of type 'Form'
Run Code Online (Sandbox Code Playgroud)
...导致不同的表达式树.请注意左下角的空引用:
. +====================+
. | MemberExpression |
. +====================+
# | |
# .Expression | | .Member
# v v
. +------------------+ +------------+
. | MemberExpression | | MemberInfo |
. +------------------+ +------------+
# | | .Name = "Text"
# .Expression | | .Member .MemberType = Property
# v v
. null +------------+
. | MemberInfo |
. +------------+
# .Name = "textBox"
# .MemberType = Field
# .DeclaringType = typeof(Form)
Run Code Online (Sandbox Code Playgroud)
在这里,你不能通过等待a来停止"下降"阶段ConstantExpression
.而是在到达空引用时停止降序.接下来,检索根对象引用,如下所示:
var mi = memberInfos.Pop();
objReference = mi.DeclaringType
.GetField(member.Name, BindingFlags.Static) // or .GetProperty!
.GetValue(null);
Run Code Online (Sandbox Code Playgroud)
从那时起的"提升"阶段与以前相同.
当然有更多的情况(例如命名参数作为根对象),但我希望到现在为止,我已经有了基本的想法,所以我会在这里切断.
Dar*_*rov 40
Expression<Func<string>> expr = () => foo.Bar;
var me = (MemberExpression)((MemberExpression)expr.Body).Expression;
var ce = (ConstantExpression)me.Expression;
var fieldInfo = ce.Value.GetType().GetField(me.Member.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var value = (Foo)fieldInfo.GetValue(ce.Value);
Run Code Online (Sandbox Code Playgroud)