访问类型特定属性时对基类型集合进行动态 Linq 查询
如何对基本类型(如 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();
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您将生成以下代码:
persons
的类型为IEnumerable
,无法转换为IEnumerable>。您想要的是添加对
Queryable.Cast
的调用,以将IPerson
对象强制转换为Person
:使用以下代码:
但是,请注意事实上,您在这里枚举了四次
persons
。如果它来自列表,则没有太大影响。如果原始枚举来自数据库查询,您可能需要确保仅枚举一次。获取列表中的结果,然后确保对其应用所有First
调用和表达式。You are generating the following code:
persons
is of typeIEnumerable<IPerson>
, which can't be cast toIEnumerable<Person
>. What you want is to add a call toQueryable.Cast
to cast theIPerson
objects toPerson
:Use the following code:
However, note that you're in fact enumerating four times
persons
here. If it comes from a list, it doesn't have much impact. If the original enumerable comes from a database query, you might want to make sure you're enumerating it only once. Get the results inside a list, then make sure all theFirst
calls and expressions are applied on it.