我正在查找一个示例,了解如何使用 Telerik 网格框架的特定部分(ASP.NET MVC3,但这与此处无关)。他们有一大段代码,它接受过滤器描述列表并构建一个表达式:
System.Linq.Expressions.Expression<Func<MyModel, bool> exp =
ExpressionBuilder.Expression<MyModel>(listOfFilters);
好的,所以我认为这很好。 Expression 包装了一个 lambda,它在 MyModel 上运行以产生一个 bool。伟大的。现在,他们的示例只是将其放入 Where 中,如下所示:
someList = someList.Where(exp);
我假设应该是“嘿,将该表达式应用于列表中的所有项目(这当然也是通用的 MyModel )。但是,VS 声称代码无法编译。我得到“没有重载存在或System.Func 有一些无效参数。
我试了一下,发现我可以编译表达式,这给出了更难看的样子
someList = someList.Where(x => exp.Compile()(x));
它确实可以编译并且可能会工作,但这让我感到不舒服,因为我现在显然在我所知道的范围之外操作。
是否有某些原因(IDE 设置、标记、过时的文档)示例的方法不起作用? 我的 hack 和示例有粗略的等效性吗? 我是否应该以不同的方式构建 hack 以避免一些可怕的问题(例如,它不会每次检查列表中的项目时都编译表达式,对吗?我认为它足够聪明吗?)
-- 编辑 是的,它是 IEnumerable。我陷入了“所有地方都是平等的”陷阱。 谢谢大家!
最佳答案
Where()
有两个版本方法:一个操作IEnumerable<T>
并采取 Func<T, bool>
, 另一个在 IQueryable<T>
上工作并采取 Expression<Func<T, bool>>
.原因是IQueryable<T>
可以表示一些远程数据,如数据库表。当您查询表格时,您不希望仅仅为了找到您要查找的单个项目而传输整个表格。
这就是为什么有 Expression
的原因:它用于表示一些代码,但以一种可以轻松处理的方式,例如转换为 SQL。或者您可以将其编译为普通 IL 代码并从中生成委托(delegate)。
如果你想在一个普通的内存列表上操作(实现了 IEnumerable<T>
,但不是 IQueryable<T>
),你根本不需要表达式,你可以一直使用委托(delegate),你的代码将可能更简单、更快。
但是如果你想使用 Expression
s,你可以,正如你发现的那样。有几个选项:
使用 the
AsQueryable()
method .这样,您将获得类似Where()
的方法与Expression
一起工作someList.AsQueryable().Where(exp)
通过调用 the
Compile()
method 编译表达式.它返回一个委托(delegate),您可以将其直接传递给Where()
.someList.Where(exp.Compile())
您的尝试实际上会为集合中的每个项目编译表达式,因此它的性能可能很差。
关于c# - Linq 表达式语法和编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9472314/