如果我有简单的课程
class Foo {
int Value { get; set; } = 20
}
class Bar {
Foo foo { get; set;} = new Foo();
}
然后我写了一个选择器表达式
var bar = new Bar();
Expression<Func<int>> fn = () => bar.foo.Value;
我知道如果我输入
var v = fn.Compile()()
v等于 20 ,表明封闭确实被捕获。我推断在表达式内部存储了对捕获的表达式目标的引用。我想从表达式中恢复原状。
例如
Bar capturedBar = GetTarget(fn);
Assert(capturedBar == bar);
和另一个功能
string selector = GetSelector(fn)
应返回
"bar.foo.A"
答案 0 :(得分:2)
您可以使用Expression Visitor技术完成此任务。
以下是主要想法的简单而肮脏的演示:
var bar = new Bar();
Expression<Func<int>> fn = () => bar.foo.Value;
BarExtractor be = new BarExtractor();
be.Visit(fn);
Bar capturedBar = be.bar;
BarExtractor类声明如下:
class BarExtractor : ExpressionVisitor {
public Bar bar;
protected override Expression VisitConstant(ConstantExpression node) {
object closureObj = node.Value;
if(closureObj != null && closureObj.GetType().Name.StartsWith("<>c__DisplayClass")) {
var barField = closureObj.GetType().GetField("bar");
if(barField != null && barField.FieldType == typeof(Bar))
bar = barField.GetValue(closureObj) as Bar;
}
return base.VisitConstant(node);
}
}