IQueryable在 LINQ 的上下文中有什么用?
IQueryable
它是否用于开发扩展方法或任何其他目的?
回答非常完整,但我想我也会从用户的角度添加一些内容......
本质上,它的工作非常类似于IEnumerable<T>- 表示可查询的数据源 - 不同之处在于各种 LINQ 方法(on Queryable)可以更具体,使用Expression树而不是委托(这是Enumerable使用的)构建查询。
IEnumerable<T>
Queryable
Expression
Enumerable
表达式树可以由您选择的 LINQ 提供程序检查并转化为实际查询 - 尽管这本身就是一种黑色艺术。
这真的取决于ElementType,Expression并且Provider- 但实际上,作为用户,您很少需要关心这一点。只有 LINQ实现者需要知道血淋淋的细节。
ElementType
Provider
重新评论;例如,我不太确定您想要什么,但请考虑 LINQ-to-SQL;这里的中心对象是 a DataContext,它代表我们的数据库包装器。这通常具有每个表的属性(例如Customers),并且表实现了IQueryable<Customer>。但是我们并没有直接使用那么多;考虑:
DataContext
Customers
IQueryable<Customer>
using(var ctx = new MyDataContext()) { var qry = from cust in ctx.Customers where cust.Region == "North" select new { cust.Id, cust.Name }; foreach(var row in qry) { Console.WriteLine("{0}: {1}", row.Id, row.Name); } }
这变成(由 C# 编译器):
var qry = ctx.Customers.Where(cust => cust.Region == "North") .Select(cust => new { cust.Id, cust.Name });
(由 C# 编译器)再次将其解释为:
var qry = Queryable.Select( Queryable.Where( ctx.Customers, cust => cust.Region == "North"), cust => new { cust.Id, cust.Name });
重要的是,静态方法Queryable采用表达式树,而不是常规的 IL,它被编译为对象模型。例如 - 只看“哪里”,这给了我们类似的东西:
var cust = Expression.Parameter(typeof(Customer), "cust"); var lambda = Expression.Lambda<Func<Customer,bool>>( Expression.Equal( Expression.Property(cust, "Region"), Expression.Constant("North") ), cust); ... Queryable.Where(ctx.Customers, lambda) ...
编译器不是为我们做了很多事情吗?这个对象模型可以被撕开,检查它的含义,然后由 TSQL 生成器重新组合在一起——给出如下内容:
SELECT c.Id, c.Name FROM [dbo].[Customer] c WHERE c.Region = 'North'
(字符串可能最终作为参数;我不记得了)
如果我们只使用委托,这一切都不可能实现。这就是Queryable/的要点IQueryable<T>:它提供了使用表达式树的入口点。
IQueryable<T>
所有这一切都非常复杂,因此编译器让我们变得轻松而轻松是一件好事。
从用户的角度来看,主要区别在于,当您使用IQueryable<T>(使用正确支持事物的提供者)时,您可以节省大量资源。
例如,如果您正在处理具有许多 ORM 系统的远程数据库,您可以选择以两种方式从表中获取数据,一种返回IEnumerable<T>,另一种返回IQueryable<T>. 例如,假设您有一个 Products 表,并且您想要获取成本大于 25 美元的所有产品。
如果你这样做:
IEnumerable<Product> products = myORM.GetProducts(); var productsOver25 = products.Where(p => p.Cost >= 25.00);
这里发生的是数据库加载所有产品,并将它们通过网络传递给您的程序。然后您的程序过滤数据。本质上,数据库做了一个SELECT * FROM Products,并返回每一个产品给你。
SELECT * FROM Products
IQueryable<T>另一方面,使用合适的提供商,您可以:
IQueryable<Product> products = myORM.GetQueryableProducts(); var productsOver25 = products.Where(p => p.Cost >= 25.00);
代码看起来一样,但这里的区别是执行的 SQL 将是SELECT * FROM Products WHERE Cost >= 25.
SELECT * FROM Products WHERE Cost >= 25
从您作为开发人员的 POV 来看,这看起来是一样的。但是,从性能的角度来看,您可能只能通过网络返回 2 条记录,而不是 20,000 条......