【问题标题】:Expression Tree how do I capture a local variable表达式树如何捕获局部变量
【发布时间】:2013-05-17 17:31:49
【问题描述】:

我目前正在努力创建动态表达式,我有以下场景,我希望帮助实现。

给定:

public class planet {
    public string name { get;set; }
}

class someTestClass {
    [Test]
    public void Planet_Exists_Statically(){
        var planetName = "earth";
        var planets = new List<planet> {new planet {name = planetName}};
        var found = planets.Exists(MakePredicate(planetName));
        Assert.IsTrue(found);
    }

    [Test]
    public void Planet_Exists_Statically(){
        var planetName = "earth";
        var planets = new List<planet> {new planet {name = planetName}};
        var found = planets.Exists(MakeDynamicPredicate(planetName));
        Assert.IsTrue(found);
    }

    private Predicate<planet> MakePredicate(string planetName){
        Expression<Predicate<planet>> pred = p => p.name == planetName;
        return pred.Compile();
    }

    private Predicate<planet> MakeDynamicPredicate(string planetName){
        var parm = Expression.Parameter(typeof(planet), "p")
        var pred = Expression.Lambda<Predicate<planet>>(
                    Expression.ReferenceEqual(
                        Expression.Property(parm, typeof(planet), "name"), 
                        **???WHAT GOES HERE???**,
                        parm);
        return pred.Compile();
    }
}

所以我的问题是我无法让 MakeDynamicPredicate 返回的谓词等于 MakePredicate 函数生成的谓词。

看了reply post from Jon Skeet,但不明白如何实现ConstantExpression,以便捕获局部变量...

任何帮助将不胜感激。

附加信息:以后我可能不知道正在使用的类,因此它最终会被抽象为更通用。

【问题讨论】:

  • 如果你提到了一些帖子(Jon Skeet 的那个),如果你链接到它会很有帮助。
  • 抱歉,我将 Jon 的名字作为他提供的答案的链接

标签: .net expression-trees local-variables constant-expression


【解决方案1】:

在您的情况下,您实际上不需要捕获任何局部变量,您可以使用Expression.Constant(planetName)

如果你随后调用它,例如,MakeDynamicPredicate("Pluto"),生成的表达式将就像你写了p =&gt; p.name == "Pluto"

【讨论】:

  • 感谢您的建议,但我希望能够将表达式返回为 p => p.name == planetName
  • @ermagana 为什么?这对您的情况没有任何影响。
  • 这个特定的实例不会有什么不同,但我正在建立一个更通用的设计,我也希望能够知道如何做,因为它应该是可能,至少据我了解。
【解决方案2】:

正如您在 Jon 的帖子中看到的,您需要一些对象来存储您的变量。对于MakePredicate,它将由编译器创建,对于MakeDynamicPredicate,您必须自己完成。首先,我们需要一个用于变量值存储的类。

class someTestClass { ... private class ValueHolder { public string Value; } ... }

现在您将 planetName 放入 ValueHolder 的一个实例中,并创建一个成员访问表达式,以便在您的谓词表达式中使用它。

private Predicate MakeDynamicPredicate(string planetName){ var valueHolder = new ValueHolder { Value = value }; var valueExpr = Expression.MakeMemberAccess( Expression.Constant(valueHolder), valueHolder.GetType().GetField("Value")); var parm = Expression.Parameter(typeof(planet), "p") var pred = Expression.Lambda>( Expression.ReferenceEqual( Expression.Property(parm, typeof(planet), "name"), valueExpr, parm); }

附:查看编译器生成的代码(例如使用 ILSpy)通常是有意义的,以更好地了解各种 epxression 是如何创建的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-20
    • 1970-01-01
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    相关资源
    最近更新 更多