在访问特定于类型的属性时对基类型的集合进行动态Linq查询
本文关键字:类型 集合 基类 查询 Linq 动态 属性 于类型 访问 | 更新日期: 2023-09-27 18:04:55
如何在基本类型(如IPerson接口)的集合上运行动态LINQ查询,但访问实现特定的属性(如Age)
我可以确定集合中的所有项都是相同的,即查看第一个类型,我可以假设其他类型都是相同的。
我需要一个UI,可以应用过滤器到不同的集合,用户看到所有可用的属性。
下面是我想要做的一个例子,表达式。调用方法抛出异常:
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
:
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)));
但是,请注意,这里实际上枚举了四次persons
。如果它来自一个列表,它不会有太大的影响。如果原始可枚举对象来自数据库查询,您可能希望确保只枚举它一次。在列表中获取结果,然后确保所有First
调用和表达式都应用于它。