表达式树 – 如何获取声明实例?

当谈到表达树时,我是新手,所以我不确定如何提出这个问题或使用什么术语。 这是我正在尝试做的过于简化的版本:

Bar bar = new Bar(); Zap(() => bar.Foo); public static void Zap(Expression<Func> source) { // HELP HERE: // I want to get the bar instance and call bar.Zim() or some other method. } 

我怎样才能在Zap方法中使用bar?

由于传递到Zap方法的表达式是树,因此您只需使用表达式树访问者遍历树并查找表达式中的第一个ConstantExpression 。 它可能按以下顺序排列:

 (((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value 

请注意, bar实例由闭包捕获,闭包实现为内部类,实例作为成员,这是第二个MemberExpression的来源。

编辑

然后你必须从生成的闭包中获取字段,如下所示:

  static void Main(string[] args) { var bar = new Bar(); bar.Foo = "Hello, Zap"; Zap(() => bar.Foo); } private class Bar { public String Foo { get; set; } } public static void Zap(Expression> source) { var param = (((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value; var type = param.GetType(); // Note that the C# compiler creates the field of the closure class // with the name of local variable that was captured in Main() var field = type.GetField("bar"); var bar = field.GetValue(param) as Bar; Debug.Assert(bar != null); Console.WriteLine(bar.Foo); } 

如果你知道“bar”的类型,你可以这样做(我在这里重复使用codekaizen的答案中的一些内容):

  static void Main(string[] args) { var bar = new Bar(); bar.Foo = "Hello, Zap"; Zap(() => bar.Foo); Console.ReadLine(); } private class Bar { public String Foo { get; set; } } public static void Zap(Expression> source) { var body = source.Body as MemberExpression; Bar test = Expression.Lambda>(body.Expression).Compile()(); Console.WriteLine(test.Foo); } 

在大多数情况下,您可以在表达式树中找到表示对象的表达式,然后编译并执行此表达式并获取对象(但顺便说一下,这不是一个非常快速的操作)。 所以,你缺少的是Compile()方法。 您可以在这里找到更多信息: 如何:执行表达式树 。

在这段代码中,我假设你总是传递一个像“()=> object.Member”这样的表达式。 对于真实场景,您需要分析您是否拥有所需的表达式(例如,如果它不是MemberExpression则抛出exception)。 或者使用ExpressionVisitor,这有点棘手。

我最近在这里回答了一个非常相似的问题: 如何在表达式树中订阅对象的事件?

站在上面的巨人的肩膀上,我提取表示表达式来源的类的实例的最终扩展方法如下所示:

 public static TIn GetSource(this Expression> property) where TIn: class { MemberExpression memberExpression = (MemberExpression)property.Body; TIn instance = Expression.Lambda>(memberExpression.Expression).Compile()(); return instance; } 

我建立在上面的所有答案之上,感谢所有人。