给定一个 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 有两件事很有趣:

.Member - 成员的PropertyInfo / FieldInfo .Expression - 为获取 .Member 的“obj”而计算的表达式

即如果您可以将.Expression 评估为“obj”,并且.MemberFieldInfo,那么您可以通过FieldInfo 上的.GetValue(obj) 获得实际值(和PropertyInfo 非常相似)。

问题是评估.Expression 非常棘手;-p

如果结果是ConstantExpression,显然你会很幸运——但在大多数情况下并非如此;它可以是ParameterExpression(在这种情况下,您需要知道要评估的实际参数值),或Expressions 的任何其他组合。

在许多情况下,一个简单的(也许是懒惰的)选择是使用.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&lt;Func&lt;object&gt;&gt;(Expression.Convert(expBody.Right, typeof(object))).Compile().Invoke() 可悲的部分:它很慢。

以上是关于给定一个 ExpressionType.MemberAccess 类型,我如何获取字段值?的主要内容,如果未能解决你的问题,请参考以下文章

给定一个数组,打印所有可能的连续子序列,其总和可被给定数 x 整除

给定一个长度为 n 的数组,找到子集的 XOR 等于给定数字的子集数

给定一个长度为 n 的数组,找到子集的 XOR 等于给定数字的子集数

实现一个函数,如果给定的字符串与给定的通配符模式匹配,则返回 True,否则返回 False

检查给定字符串是不是等效于给定字符串集中的至少一个字符串的有效方法

给定一个字典,通过查找这个字典,替换给定的字符串中的中文为英文