ベースタイプのコレクション(IPersonインターフェイスなど)で動的LINQクエリを実行しながら、実装固有のプロパティ(Ageなど)にアクセスするにはどうすればよいですか。
コレクション内のすべてのアイテムが同じであることを確認できます。つまり、最初のタイプを見ると、他のアイテムは同じであると想定できます。
さまざまなコレクションにフィルターを適用できる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();
}
}
}
次のコードを生成しています。
persons.Where((Person p) => p.Age > 30)
persons
タイプであるIEnumerable<IPerson>
にキャストすることはできません、 IEnumerable<Person
>。 Queryable.Cast
への呼び出しを追加して、 IPerson
オブジェクトをPerson
にキャストするIPerson
ます。
persons.Cast<Person>().Where(p => p.Age > 30)
次のコードを使用します。
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)));
ただし、ここでは実際に4倍のpersons
列挙していることに注意してください。リストからのものである場合、それはあまり影響を与えません。元の列挙可能なものがデータベースクエリからのものである場合は、それを1回だけ列挙していることを確認することをお勧めします。リスト内の結果を取得し、 First
呼び出しと式がすべて適用されていることを確認します。