1

基本型 (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();
        }
    }
}
4

1 に答える 1

2

次のコードを生成しています。

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

persons>IEnumerable<IPerson>にキャストできない型です。IEnumerable<Personあなたが望むのは、オブジェクトをQueryable.Castにキャストするための呼び出しを追加することです:IPersonPerson

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呼び出しと式がリストに適用されていることを確認します。

于 2011-08-08T19:41:41.030 に答える