给定一个 ExpressionType.MemberAccess 类型,我如何获取字段值?
Posted
技术标签:
【中文标题】给定一个 ExpressionType.MemberAccess 类型,我如何获取字段值?【英文标题】:Given a type ExpressionType.MemberAccess, how do i get the field value? 【发布时间】:2010-09-19 07:41:49 【问题描述】:我正在解析一个表达式树。给定 ExpressionType.MemberAccess 的 NodeType,我如何获取该字段的值?
来自 C# MSDN 文档: MemberAccess 是表示从字段或属性读取的节点。
代码 sn-p 将非常非常有用。提前谢谢!!!
我的代码如下所示:
public static List<T> Filter(Expression<Func<T, bool>> filterExp)
//the expression is indeed a binary expression in this case
BinaryExpression expBody = filterExp.Body as BinaryExpression;
if (expBody.Left.NodeType == ExpressionType.MemberAccess)
//do something with ((MemberExpressionexpBody.Left).Name
//right hand side is indeed member access. in fact, the value comes from //aspdroplist.selectedvalue
if (expBody.Right.NodeType == ExpressionType.MemberAccess)
//how do i get the value of aspdroplist.selected value?? note: it's non-static
//return a list
【问题讨论】:
【参考方案1】:[为清晰起见更新]
首先;将Expression
转换为MemberExpression
。
MemberExpression
有两件事很有趣:
PropertyInfo
/ FieldInfo
.Expression - 为获取 .Member 的“obj”而计算的表达式
即如果您可以将.Expression
评估为“obj”,并且.Member
是FieldInfo
,那么您可以通过FieldInfo
上的.GetValue(obj)
获得实际值(和PropertyInfo
非常相似)。
问题是评估.Expression
非常棘手;-p
如果结果是ConstantExpression
,显然你会很幸运——但在大多数情况下并非如此;它可以是ParameterExpression
(在这种情况下,您需要知道要评估的实际参数值),或Expression
s 的任何其他组合。
在许多情况下,一个简单的(也许是懒惰的)选择是使用.Compile()
让 .NET 框架完成繁重的工作;然后,您可以将 lambda 评估为类型化委托(传入 lambda 所需的任何参数)。然而,这并不总是一种选择。
展示这有多复杂;考虑这个简单的例子(我在每一步都进行了硬编码,而不是测试等):
using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo
public string Bar get; set;
static class Program
static void Main()
Foo foo = new Foo Bar = "abc";
Expression<Func<string>> func = () => foo.Bar;
MemberExpression outerMember = (MemberExpression)func.Body;
PropertyInfo outerProp = (PropertyInfo) outerMember.Member;
MemberExpression innerMember = (MemberExpression)outerMember.Expression;
FieldInfo innerField = (FieldInfo)innerMember.Member;
ConstantExpression ce = (ConstantExpression) innerMember.Expression;
object innerObj = ce.Value;
object outerObj = innerField.GetValue(innerObj);
string value = (string) outerProp.GetValue(outerObj, null);
【讨论】:
非常感谢马克。 .Expression 属性的值是......更有趣的东西:value(ASP.usercontrols_mycontro_ascx).controlname 我在泛型和反射方面做了很多工作,所以通过 propertyinfo/fieldinfo 检索值不起作用,因为我不确定从哪里拉引用对象...我可以拉那个吗来自成员表达式或方法信息? 它会起作用...但问题是您需要将 .Expression 评估为作为 FieldInfo/PropertyInfo 的“obj”输入的值。你不能只使用 .Compile() 并作为委托执行 lambda 吗?比解析简单多了…… 请注意,如果 lambda 是参数化的,但您没有特定的参数 - 那么您会遇到困难......但是像 ConstantExpression 这样的东西应该可以正常工作。 非常感谢马克!!!真的......超越这里。最终问题是左侧是二进制表达式......而右侧不是常量表达式。我将用一些代码更新我的问题【参考方案2】:非常感谢上面的 Marc Gravell。我真的很感谢他的帮助。
事实证明,就我而言。该问题可以通过以下方式解决:
object value = Expression.Lambda(expBody.Right).Compile().DynamicInvoke();
再次感谢马克!
【讨论】:
或更好的object value = Expression.Lambda<Func<object>>(Expression.Convert(expBody.Right, typeof(object))).Compile().Invoke()
可悲的部分:它很慢。以上是关于给定一个 ExpressionType.MemberAccess 类型,我如何获取字段值?的主要内容,如果未能解决你的问题,请参考以下文章
给定一个数组,打印所有可能的连续子序列,其总和可被给定数 x 整除
给定一个长度为 n 的数组,找到子集的 XOR 等于给定数字的子集数
给定一个长度为 n 的数组,找到子集的 XOR 等于给定数字的子集数
实现一个函数,如果给定的字符串与给定的通配符模式匹配,则返回 True,否则返回 False