2011-08-08 3 views
1

ベースタイプ(IPersonインタフェースなど)のコレクションに対して動的LINQクエリを実行できますが、実装固有のプロパティ(Ageなど)にアクセスするにはどうすればよいですか。タイプ固有のプロパティにアクセスする際の基底型のコレクションの動的Linqクエリ

コレクション内のすべてのアイテムが同じであることを確認できます。つまり、他のアイテムが同じであると仮定できる最初のタイプを確認できます。

フィルタをさまざまなコレクションに適用できるUIに必要なのは、利用可能なすべてのプロパティが表示されます。ここで

は私がやりたいものの例ですが、Expression.Callメソッドが例外をスロー:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Linq.Dynamic; 
using DynamicExpression = System.Linq.Dynamic.DynamicExpression; 

namespace DynamicLinqTest 
{ 
    public interface IPerson 
    { 
     string Name { get; set; } 
    } 
    public class Person : IPerson 
    { 
     public string Name { get; set; } 
     public int Age { get; set; } 
     public double Income { get; set; } 
    } 

    class Program 
    { 
     public static IEnumerable<Person> GetPersons() 
     { 
      yield return new Person { Name = "Sam", Age = 26, Income = 50000 }; 
      yield return new Person { Name = "Rick", Age = 27, Income = 0 }; 
      yield return new Person { Name = "Joe", Age = 45, Income = 35000 }; 
      yield return new Person { Name = "Bill", Age = 31, Income = 40000 }; 
      yield return new Person { Name = "Fred", Age = 56, Income = 155000 }; 
     } 

     static void Main(string[] args) 
     { 
      IEnumerable<IPerson> persons = GetPersons(); 
      var personsQueriable = persons.AsQueryable(); 

      //what I would like to do: 
      // personsQueriable.Where("Age > 30"); 

      var l = DynamicExpression.ParseLambda(persons.First().GetType(), typeof(bool), "Age > 30"); 
      var filtered = personsQueriable.Provider.CreateQuery(
       Expression.Call(
        typeof(Queryable), "Where", 
        new Type[] { persons.First().GetType() }, 
        personsQueriable.Expression, Expression.Quote(l))); 

      ObjectDumper.Write(filtered); 
      Console.Read(); 
     } 
    } 
} 

答えて

2

あなたは以下のコード生成されています

persons.Where((Person p) => p.Age > 30) 

personsは型でありますIEnumerable<IPerson>、これはIEnumerable<Personにキャストできません>。何が欲しいのはPersonIPersonオブジェクトをキャストするQueryable.Castへの呼び出しを追加することです:あなたは実際には4回personsを列挙していることに注意してください、しかし

var castedQueryable = personsQueriable.Provider.CreateQuery(
    Expression.Call(
     typeof(Queryable), "Cast", 
     new Type[] { persons.First().GetType() }, 
     personsQueriable.Expression)); 

var l = DynamicExpression.ParseLambda(persons.First().GetType(), typeof(bool), "Age > 30"); 
var filtered = personsQueriable.Provider.CreateQuery(
    Expression.Call(
     typeof(Queryable), "Where", 
     new Type[] { persons.First().GetType() }, 
     castedQueryable.Expression, Expression.Quote(l))); 

persons.Cast<Person>().Where(p => p.Age > 30) 

は、次のコードを使用しますここに。リストから来たものであれば、大きな影響はありません。元の列挙型がデータベースクエリから来た場合は、列挙型を1回だけ列挙したいことがあります。結果をリストの中に入れてから、Firstの呼び出しと式がすべて適用されていることを確認してください。

+0

甘い溶液!私もそのトラックに乗っていたが、私はそれを行う方法を知らなかった。本当にありがとう!私は複数の列挙の問題を認識していましたが、その例が可能な限り単純であることを確認しました。 – lukebuehler

関連する問題