2012-02-27 63 views
4

我正在查找一个示例如何使用Telerik网格框架的特定部分(ASP.NET MVC3,但这不是真的在这里相关)。他们有一段代码,这需要过滤器说明的列表,并建立一个表达式:Linq表达式语法和编译

System.Linq.Expressions.Expression<Func<MyModel, bool> exp = 
       ExpressionBuilder.Expression<MyModel>(listOfFilters); 

好了,我觉得这很好。表达式包装一个lambda,它在MyModel上运行以生成一个布尔值。大。现在,他们的例子只是下降到这一点,像这样一个地方:

someList = someList.Where(exp); 

对此我推测应该是“哎应用该表达列表中的所有项目(这当然是通用为MyModel太)然而, VS声称代码不能编译,我得到“没有超载存在或者System.Func有一些无效参数”

我玩弄了它,发现我可以编译表达式,

someList = someList.Where(x => exp.Compile()(x)); 

哪个编译和会pro可以工作,但这让我感到不舒服,因为我现在明显在我所知道的范围之外工作。

为什么(IDE设置,标志,陈旧文档)示例的方法不起作用有一些原因吗? 对我的黑客和示例有一个粗略的等价关系吗? 我应该以不同的方式构建该hack以避免一些可怕的问题(比如,它不会每次编译表达式时都检查表达式中的项目,对吗?我认为它足够聪明)

- - 编辑 是的,它是IEnumerable。我陷入了“所有Wheres都是平等的”陷阱。 谢谢大家!

回答

2

您是否尝试过只是做

someList = someList.Where(exp.Compile()); 

如果someList是IEnumerable,你将需要使用exp.Compile()返回一个Func<MyModel,bool>

如果someList是IQueryable你可以使用exp.Compile()或者你可以使用exp哪些是Expression<Func<MyModel, bool>>

+0

有趣。这也有用,所以我可以清理一下我的代码。我想那个问题是为什么我需要这样做呢? – Mikeb 2012-02-27 21:15:12

+1

这是正确的。附注:这有可怕的表现,因为编译表达式非常昂贵。 – usr 2012-02-27 21:15:21

+4

@Mikeb IEnumerable .Where()需要一个Func,而不是一个表达式,对吧?你的Expression.Compile正在生成一个Func - 这可能是它的原因。但是,鉴于Telerik示例中的用法,我会看看Telerik框架是否具有扩展方法。 – 2012-02-27 21:18:58

2

someList是什么类型?我假设List<T>。没有扩展方法Where允许在List<T>IEnumerable<T>上的Expression<Func<T, bool>>

您可能习惯于将表达式发送给可查询的表达式。 IQueryable<T>确实有一个Where扩展方法,允许Expression<Func<T, bool>>。要访问它,你会做以下

var someQueryable = someList.AsQueryable().Where(exp); 

返回类型将由IQueryable<T>。要将它放回someList,您需要添加一个AsEnumerable()ToList(),具体取决于someList的类型。

这可能不是最好的方法,但它可以让你按照预期使用exp

+0

http://msdn.microsoft.com/en-us/library/bb534803.aspx – 2012-02-27 21:21:24

+0

@ScottW不允许表达式。它允许'Func '。 – cadrell0 2012-02-27 21:23:57

+0

哦,我的错误,没有注意到表情的一部分。 – 2012-02-27 21:24:43

3

有该Where()方法的两个版本:一个运行在IEnumerable<T>并采取Func<T, bool>,其他作品上IQueryable<T>并采取Expression<Func<T, bool>>。原因是IQueryable<T>可以代表一些远程数据,如数据库表。当你查询表格时,你不想传送整个表格来找到你要查找的单个项目。

这就是为什么存在Expression的原因:它用于表示某些代码,但是可以轻松处理,例如转换为SQL。或者你可以将它编译成普通的IL代码,并将其委托出去。

如果你想一个正常的内存列表进行操作(实现IEnumerable<T>,但不IQueryable<T>),你并不需要在所有的表情,你可以与代表工作,所有的时间和你的代码很可能是更简单并且更快。

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

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

    someList.AsQueryable().Where(exp) 
    
  2. 通过调用the Compile() method编译的表达。它会返回一个代理,您可以直接将其传递给Where()

    someList.Where(exp.Compile()) 
    

您试图将实际编译集合中的每个项目的表达,所以它可能会有糟糕的表现。