返回IEnumerable和IQueryable的区别
返回IEnumerable和IQueryable的区别
在返回 IQueryable
和 IEnumerable
时有什么区别?应该在什么情况下优先选择其中一个?
IQueryable custs = from c in db.Customers where c.City == "" select c; IEnumerable custs = from c in db.Customers where c.City == "" select c;
两者都是延迟执行的,但应该在什么情况下更倾向于使用其中一个?
顶部答案很好,但它没有提到表达式树,这解释了这两个接口的“如何”不同。基本上,有两组相同的LINQ扩展。`Where()`,`Sum()`,`Count()`,`FirstOrDefault()`等都有两个版本:一个接受函数,另一个接受表达式。
- `IEnumerable`版本签名是:`Where(Func
- `IQueryable`版本签名是:`Where(Expression
您可能一直在使用这两种方式而没有意识到,因为两者都使用相同的语法进行调用:
例如,`Where(x => x.City == "
在`IEnumerable`集合上使用`Where()`时,编译器将编译的函数传递给`Where()`。
当在`IQueryable`集合上使用`Where()`时,编译器将表达式树传递给`Where()`。表达式树就像反射系统,但用于代码。编译器将您的代码转换为数据结构,该数据结构以易于消化的格式描述您的代码执行的操作。
为什么要麻烦这个表达式树?我只想要`Where()`来筛选我的数据。
主要原因是EF和Linq2SQL ORM均可以将表达式树直接转换为SQL,其中您的代码将更快地执行。哦,那听起来像是一个免费的性能提升,那我应该在这种情况下到处使用AsQueryable()
吗? 不,IQueryable
只有在底层数据提供程序可以处理它时才有用。将像常规的List
这样的东西转换为IQueryable
不会给您带来任何好处。
是的,两者都会给你延迟执行。
区别在于IQueryable
是允许LINQ-to-SQL(实际上是LINQ-to-anything)工作的接口。因此,如果你在IQueryable
上进一步细化你的查询,那么如果可能的话,该查询将在数据库中执行。
对于IEnumerable
,它将是LINQ-to-object,这意味着该原始查询的所有匹配对象都必须从数据库加载到内存中。
在代码中:
IQueryablecusts = ...; // Later on... var goldCustomers = custs.Where(c => c.IsGold);
该代码将只执行SQL以选择黄金客户。另一方面,下面的代码将在数据库中执行原始查询,然后在内存中过滤掉非黄金客户:
IEnumerablecusts = ...; // Later on... var goldCustomers = custs.Where(c => c.IsGold);
这是一个相当重要的区别,使用IQueryable
在许多情况下可以防止从数据库返回过多的行。另一个主要例子是进行分页:如果你在IQueryable
上使用Take
和Skip
,你只会得到所请求的行数;如果在IEnumerable
上执行,会导致所有行都在内存中加载。