如何解析一个简单的捕获闭包表达式并获取目标对象和选择器

时间:2016-06-17 06:13:48

标签: c# .net closures expression-trees

如果我有简单的课程

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"

1 个答案:

答案 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);
    }
}