我正在查找如何使用Telerik网格框架的特定部分(ASP.NET MVC3,但这在这里并不真正相关)的示例。他们有一大块代码,它接受一个过滤器描述列表并构建一个表达式:
System.Linq.Expressions.Expression<Func<MyModel, bool> exp =
ExpressionBuilder.Expression<MyModel>(listOfFilters);
好的,所以我认为没关系。 Expression包含一个lambda,它在MyModel上运行以产生一个bool。大。现在,他们的例子简单地将其放入一个类似的地方:
someList = someList.Where(exp);
我认为应该是“将表达式应用于列表中的所有项目(当然也是通用的MyModel)。但是,VS声称代码无法编译。我得到”没有过载存在或System.Func有一些无效的参数“。
我玩弄它并发现我可以编译表达式,这使得看起来更不合时宜
someList = someList.Where(x => exp.Compile()(x));
哪个编译并且可能会起作用,但它让我感到不舒服,因为我现在显然在我所知道的范围之外操作。
是否有某些原因(IDE设置,标记,陈旧文档)示例的方法不起作用? 我的黑客和例子有一个粗略的等价吗? 我是否应该以不同方式构建该hack以避免一些可怕的问题(比如,它不会在每次检查列表中的项目时编译表达式,对吧?我觉得它足够聪明了吗?)
- 编辑 是的,它是IEnumerable。我陷入了“所有人都被创造平等”的陷阱。 谢谢大家!
答案 0 :(得分:4)
Where()
方法有两个版本:一个在IEnumerable<T>
上运行,另一个在Func<T, bool>
上运行,另一个在IQueryable<T>
上运行,需要Expression<Func<T, bool>>
。原因是IQueryable<T>
可以表示一些远程数据,如数据库表。当您查询表格时,您不希望传输整个表格,只是为了找到您要查找的单个项目。
这就是为什么存在Expression
的原因:它用于表示一些代码,但是以一种易于处理的方式,例如转换为SQL。或者您可以将其编译为普通的IL代码并从中创建委托。
如果你想在正常的内存列表(实现IEnumerable<T>
而不是IQueryable<T>
)上操作,你根本不需要表达式,你可以一直使用代理并且您的代码可能更简单,更快。
但是,如果您想使用Expression
,您可以,正如您所发现的那样。有几种选择:
使用the AsQueryable()
method。这样,您将获得与Where()
s一起使用的Expression
等方法。
someList.AsQueryable().Where(exp)
通过调用the Compile()
method编译表达式。它返回一个可以直接传递给Where()
的委托。
someList.Where(exp.Compile())
您的尝试实际上会为集合中的每个项目编译表达式,因此它可能会有糟糕的性能。
答案 1 :(得分:2)
你有没有尝试过做
someList = someList.Where(exp.Compile());
如果某个列表是IEnumerable
,则需要使用exp.Compile()
返回Func<MyModel,bool>
如果someList是IQueryable
,您可以使用exp.Compile()
,或者您可以使用exp
Expression<Func<MyModel, bool>>
答案 2 :(得分:2)
someList的类型是什么?我假设List<T>
。没有扩展方法Where
允许在Expression<Func<T, bool>>
或List<T>
上IEnumerable<T>
。
您可能习惯于将表达式发送到可查询对象。 IQueryable<T>
确实有一个允许Where
的{{1}}扩展方法。要访问它,您必须执行以下操作
Expression<Func<T, bool>>
该返回类型将由var someQueryable = someList.AsQueryable().Where(exp);
提供。要将其放回someList,您需要添加IQueryable<T>
或AsEnumerable()
,具体取决于someList的类型。
这可能不是最好的方法,但它可以让您按预期使用ToList()
。