Linq表达式语法和编译

时间:2012-02-27 21:09:00

标签: c# linq expression

我正在查找如何使用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。我陷入了“所有人都被创造平等”的陷阱。 谢谢大家!

3 个答案:

答案 0 :(得分:4)

Where()方法有两个版本:一个在IEnumerable<T>上运行,另一个在Func<T, bool>上运行,另一个在IQueryable<T>上运行,需要Expression<Func<T, bool>>。原因是IQueryable<T>可以表示一些远程数据,如数据库表。当您查询表格时,您不希望传输整个表格,只是为了找到您要查找的单个项目。

这就是为什么存在Expression的原因:它用于表示一些代码,但是以一种易于处理的方式,例如转换为SQL。或者您可以将其编译为普通的IL代码并从中创建委托。

如果你想在正常的内存列表(实现IEnumerable<T>而不是IQueryable<T>)上操作,你根本不需要表达式,你可以一直使用代理并且您的代码可能更简单,更快。

但是,如果您想使用Expression,您可以,正如您所发现的那样。有几种选择:

  1. 使用the AsQueryable() method。这样,您将获得与Where() s一起使用的Expression等方法。

    someList.AsQueryable().Where(exp)
    
  2. 通过调用the Compile() method编译表达式。它返回一个可以直接传递给Where()的委托。

    someList.Where(exp.Compile())
    
  3. 您的尝试实际上会为集合中的每个项目编译表达式,因此它可能会有糟糕的性能。

答案 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()