2009-05-25 14 views
-2

私は、ユーザーが入力したクエリを表す式ツリーを作成する必要があります。私はユーザー入力のすべての可能なケースを作成する時間がないので、私は表現木がこれを解決するのに役立つだろうと思った。式と述語の問題

ほとんどの場合、それがあります。しかし、私はちょっと困っています。私は動的に作成された式でList.Findを実行しようとしている以下のコードにあります。 mは私がこれまでの表現と

s => s == "cookie" 

、何の問題を作成するようもらいました

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

です

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

:式は、短期では、これです。私が持っている唯一の問題はそれが理解できる例外を与えるので

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

のようにパラメータとしてラムダと言っメソッドを呼び出すために式を作成している

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

が存在するために、私はまたMETHODINFOを宣言したこと

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()); 
} 
+0

私は「動的」ユーザー入力がLINQのでは挑戦のビットであることを知っているが、ユーザーの場合フィルタリングするフィールドに異なる値を指定するか、同じ要素に異なるフィルタを指定するだけで、元のフィルタにWhere句を追加してフィルタ自体に入力を使用できます。つまり、要するに、なぜこのような問題が起こっているのか、なぜ必要な場合にWhere節を追加できないのかは完全には分かりません。 –

+0

@Frans、私は単純にユーザーが静的に定義されたフィールドに異なる値を指定することはできません。私は完全に動的な解決策が必要です。a)バルクを削減します。維持する必要のあるコードと、c)すべてのクラスライブラリの新しいクラスに拡張性を提供する必要があります。 –

答えて

2

参加者は異なるタイプを有します。ラムダ式は実行時にFunc<T, TResult>にコンパイルされます。

次のことを試してください:あなたはまた、一般的なLambda Functionを使用することができます

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

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

ええ、私はそれらが異なるタイプであることは分かっていましたが、Func を述語に変換するほどスマートになると思ったのですが、述語がboolを返すので...私は仕事に戻ります - ありがとう! –

+0

私はそれが実行時にコンパイルすることも知っていますが、問題はExpression.CallがExpressionを期待しているので、プレディケートをパラメータとして送信できないことでした。コードがその問題を解決するようです。私が言ったように、私は明日仕事でそれを試してみましょう。再度、感謝します。 =) –

+0

素晴らしいです。そのような単純な変更。ありがとう。 =) –

0

メッセージを見れば、それは述語がの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) 

e。 string!= MyClass。

わかりました。

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

Exists方法(及びFindPredicate<T>を期待:

+0

私のエラーとは何の関係もありません。 =) –

+0

あなたはそうです、私は完全にそのすべてを間違って読むことができました。つまり、ブルーノの提案を試してください。 – kastermester