共有两组 LINQ 标准查询运算符,一组在类型为 IEnumerable< T> 的对象上运行,另一组在类型为 IQueryable< T>的对象上运行。构成每组运算符的方法分别是 Enumerable 和 Queryable 类的静态成员。这些方法被定义为作为方法运行目标的类型的“扩展方法”。这意味着可以使用静态方法语法或实例方法语法来调用它们。
大家应该还记得,上节我们说过linq查询要执行在clr上师把查询语句变成扩展方法来执行,这两套东西不仅返回类型不同连所定义的扩展方法都不同,所以 我们完全可以把这2套东西理解成完全不同的东西,那么,什么时候用IEnumerable< T> , 什么时候用IQueryable< T> 呢? 让我们再来看看msdn的介绍:
对于在内存中集合上运行的方法(即扩展 IEnumerable< T> 的那些方法),返回的可枚举对象将捕获传递到方法的参数。在枚举该对象时,将使用查询运算符的逻辑,并返回查询结果。
与之相反,扩展 IQueryable < T> 的方法不会实现任何查询行为,但会生成一个表示要执行的查询的表达式树。查询处理由源 IQueryable< T> 对象处理。
一言以蔽之,本地数据源用IEnumerable< T> , 并且查询的逻辑可以直接用你所定义的方法的逻辑(因为有上下文),远程数据源用IQueryable< T> ,无法直接 使用你所定义的方法的逻辑,必须先生成表达式树,查询由源对象处理。
下面我们再来看一个例子来证明这是两套完全不同的东西:
首先是本地数据源:
List<string> names = new List<string> { "Cai", "Wxied", "Beauty" };
然后我们看看names的where方法
VS的智能提示会告诉我们(sorry,这个地方实在不好截图,大家可以自 己尝试,我先给大家描述下)这个扩展方法有2个重载,必须传入Func<T>,返回IEnumerable< T>。
再提一点知识,Func<T>叫谓语表达式,相当于一 个委托, 我认为 ,之所以可以直接传Func<T>是因为本地数据源可 以直接执行方法的逻辑。
再让我们来看看一个远程数据源:
DataClasses1DataContext dataContext = new DataClasses1DataContext();
dataContext.Customers.Where这个方法有4个重载。必须传入 Expression<Func<T>>,返回IQueryable< T>。
大家和上面对比一下,就会发现本地数据源和远程数据源的扩展方法完全不一样,而且远程数据源不能直接传Func<T>,必须用一个 Expression来包装这个Func<T>,正好又从一个方面验证了我们之前所提到的知识。
总结之,IEnumerable<T>查询必须在本地执行.并且执行查询前我们必须把所有的数据加载到本地.而且更多的时候.加载的数据有大 量的数据是我们不需要的无效数据.但是我们却不得不传输更多的数据.做更多的无用功.而IQueryable<T>却总能只提供你所需要的数 据.大大减少了数据的传输.这就好比我们在小作坊下订单.小作坊老板跟我们说.他的货刚好比你所需要的多出一些.你只能要了它.不然剩下一点他不好卖等 等.而大工厂却不会出现这种状况.