-2

ユーザーによるクエリ入力を表す式ツリーを作成する必要があるという、ちょっとした課題があります。ユーザー入力の考えられるすべてのケースを作成する時間がないため、式ツリーがこれを解決するのに役立つと考えました。

ほとんどの場合、それはあります。しかし、私は少し困惑しています。以下のコードでは、動的に作成された式で List.Find を実行しようとしています。式は、要するに次のとおりです。

list.Find(m => m.ListOfStrings.Exists(s => s == "cookie"));

m はどこですか

class MyClass
{
    public List<string> ListOfStrings { get; set; }
}

作成するまでになりました

s => s == "cookie"

式で、問題ありません。Exists の methodinfo も宣言しました

var existsMethod = typeof(MyClass)
        .GetProperty("ListOfStrings")
        .PropertyType
        .GetMethod("Exists");

私が抱えている唯一の問題は、ラムダをパラメーターとして使用して上記のメソッドを呼び出す式を作成することです

var findLambda = Expression.Lambda(
    Expression.Call(
        Expression.Property(
            Expression.Parameter(typeof(MyClass), "m"),
            typeof(MyClass).GetProperty("ListOfStrings")),
        existsMethod,
        existsLambda),
    Expression.Parameter(
        typeof (MyClass),
        "m"));

それは理解できる例外を与えます

Expression of type 'System.Func`2[System.String,System.Boolean]' cannot be used for parameter of type 'System.Predicate`1[System.String]' of method 'Boolean Exists(System.Predicate`1[System.String])'

どうすればこれを克服できますか?

完全なコード:

private class MyClass
{
    public List<string> ListOfStrings { get; set; }
}

public void SomeMethod()
{
    var myObject = new MyClass();
    myObject.ListOfStrings = new List<string>();
    myObject.ListOfStrings.Add("cookie");
    myObject.ListOfStrings.Add("biscuit");

    List<MyClass> list = new List<MyClass>();
    list.Add(myObject);

    var existsLambda = Expression.Lambda(
        Expression.Equal(
            Expression.Parameter(typeof(string), "s"),
            Expression.Constant("cookie")),
        Expression.Parameter(typeof(string), "s"));

    var existsMethod = typeof(MyClass).GetProperty("ListOfStrings").PropertyType.GetMethod("Exists");

    var findLambda = Expression.Lambda(
        Expression.Call(
            Expression.Property(
                Expression.Parameter(typeof(MyClass), "m"),
                typeof(MyClass).GetProperty("ListOfStrings")),
            existsMethod,
            existsLambda),
        Expression.Parameter(
            typeof (MyClass),
            "m"));

    list.Find((Predicate<MyClass>)findLambda.Compile());
}
4

2 に答える 2

2

デリゲートにはさまざまなタイプがあります。

public delegate bool Predicate<T>(T obj);
public delegate TResult Func<T, TResult>(T arg);

Existsメソッド (および)はFindexpectPredicate<T>です。Lambda 式は、実行時に にコンパイルされますFunc<T, TResult>

次のことを試してください。

var existsLambda = Expression.Lambda(typeof(Predicate<string>), 
                Expression.Equal(
                    Expression.Parameter(typeof(string), "s"),
                    Expression.Constant("cookie")),
                Expression.Parameter(typeof(string), "s"));

汎用のLambda 関数を使用することもできます:

var existsLambda = Expression.Lambda<Predicate<string>>(Expression.Equal(
                    Expression.Parameter(typeof(string), "s"),
                    Expression.Constant("cookie")),
                Expression.Parameter(typeof(string), "s"));
于 2009-05-25T16:26:12.747 に答える
0

メッセージを見ると、Predicate は Func と互換性がないことがわかります。

現在、述語は次のように定義されています。

public delegate bool Predicate<T>(
    T obj
)

そして、あなたは Func を持っています:

public delegate TResult Func<T, Result>(
    T arg1
)

まとめると、これら 2 つのデリゲートに互換性を持たせようとしています。

public delegate bool MyClassPredicate ( MyClass obj )
public delegate bool StringFunc ( string arg1 )

すなわち。文字列 != MyClass.

それが理にかなっていることを願っています。

于 2009-05-25T16:19:44.743 に答える