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 を使用) を確認することは理にかなっています。

于 2013-05-17T09:31:49.433 に答える
1

あなたの場合、実際にローカル変数をキャプチャする必要はありません。単に使用できますExpression.Constant(planetName)

次に、たとえば で呼び出すとMakeDynamicPredicate("Pluto")、生成された式は と書いたかのようになりますp => p.name == "Pluto"

于 2013-05-15T17:16:09.783 に答える