0

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

给定:

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 函数生成的谓词。

我阅读了Jon Skeet 的回复帖子,但不明白如何实现 ConstantExpression 以便捕获局部变量...

任何帮助将不胜感激。

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

4

2 回答 2

1

正如您在 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);

}

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

于 2013-05-17T09:31:49.433 回答
1

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

例如,如果您随后使用 调用它,MakeDynamicPredicate("Pluto")生成的表达式将与您编写的一样p => p.name == "Pluto"

于 2013-05-15T17:16:09.783 回答