文档章节

返回IEnumerable <T> 与IQueryable相比 <T> [关闭]

 技术盛宴
发布于 2019/12/13 11:13
字数 1761
阅读 15
收藏 0

返回IQueryable<T>IEnumerable<T>之间有什么区别?

IQueryable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;

IEnumerable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;

两者都会延迟执行吗?什么时候应该优先于另一个?


#1楼

一般来说,我会建议如下:

  • 返回IQueryable<T>如果要使用您的方法启用开发人员来优化您在执行之前返回的查询。

  • 如果要传输一组对象以进行枚举,则返回IEnumerable

想象一下IQueryable就是它的IQueryable - 数据的“查询”(如果你愿意,可以改进)。 IEnumerable是一组可以枚举的对象(已经接收或创建过)。


#2楼

通常,您希望保留查询的原始静态类型,直到重要为止。

因此,您可以将变量定义为'var'而不是IQueryable<>IEnumerable<>并且您将知道您没有更改类型。

如果你从IQueryable<> ,你通常希望将它保持为IQueryable<>直到有一些令人信服的理由来改变它。 这样做的原因是您希望为查询处理器提供尽可能多的信息。 例如,如果您只使用10个结果(您已调用Take(10) ),那么您希望SQL Server知道这一点,以便它可以优化其查询计划并仅向您发送您将使用的数据。

将类型从IQueryable<>更改为IEnumerable<>一个令人信服的理由可能是您正在调用某个扩展函数,即您的特定对象中的IQueryable<>的实现无法处理或处理效率低下。 在这种情况下,您可能希望将类型转换为IEnumerable<> (通过分配给IEnumerable<>类型的变量或通过使用AsEnumerable扩展方法),以便您调用的扩展函数最终成为Enumerable类而不是Queryable类。


#3楼

我最近遇到了IEnumerable IQueryable 。 首先使用的算法执行IQueryable查询以获得一组结果。 然后将这些项传递给foreach循环,将项实例化为实体框架(EF)类。 然后在Linq to Entity查询的from子句中使用此EF类,导致结果为IEnumerable

我是EF和Linq for Entities的新手,所以需要一段时间来弄清楚瓶颈是什么。 使用MiniProfiling,我找到了查询,然后将所有单个操作转换为单个IQueryable Linq for Entities查询。 IEnumerable耗时15秒, IQueryable需要0.5秒才能执行。 涉及到三个表,在阅读之后,我认为IEnumerable查询实际上形成了一个三表交叉产品并过滤结果。

尝试使用IQueryables作为经验法则,并对您的工作进行分析,以使您的更改可衡量。


#4楼

有一篇博客文章,内容简要介绍了IEnumerable<T>滥用如何极大地影响LINQ查询性能: 实体框架:IQueryable与IEnumerable

如果我们深入挖掘并查看源代码,我们可以看到IEnumerable<T>显然有不同的扩展方法:

// Type: System.Linq.Enumerable
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
public static class Enumerable
{
    public static IEnumerable<TSource> Where<TSource>(
        this IEnumerable<TSource> source, 
        Func<TSource, bool> predicate)
    {
        return (IEnumerable<TSource>) 
            new Enumerable.WhereEnumerableIterator<TSource>(source, predicate);
    }
}

IQueryable<T>

// Type: System.Linq.Queryable
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
public static class Queryable
{
    public static IQueryable<TSource> Where<TSource>(
        this IQueryable<TSource> source, 
        Expression<Func<TSource, bool>> predicate)
    {
        return source.Provider.CreateQuery<TSource>(
            Expression.Call(
                null, 
                ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(
                    new Type[] { typeof(TSource) }), 
                    new Expression[] 
                        { source.Expression, Expression.Quote(predicate) }));
    }
}

第一个返回可枚举迭代器,第二个通过IQueryable源中指定的查询提供程序创建查询。


#5楼

之前已经说过很多,但是以更技术性的方式回到根源:

  1. IEnumerable 是内存中可以枚举的对象集合 - 一个内存序列,可以迭代(在foreach循环中使其变得容易,尽管你只能使用IEnumerator )。 它们按原样驻留在内存中。
  2. IQueryable 是一个表达式树 ,它可以在某个时刻被翻译成其他东西, 并能够枚举最终结果 。 我想这就是让大多数人感到困惑的原因。

他们显然有不同的内涵。

IQueryable表示一个表达式树(简单地称为查询),一旦调用发布API,它将被底层查询提供者转换为其他内容树,如LINQ聚合函数(Sum,Count等)或ToList [Array,Dictionary, ...]。 IQueryable对象还实现IEnumerableIEnumerable<T>这样如果它们表示查询,则可以迭代该查询的结果。 这意味着IQueryable不必仅是查询。 正确的术语是表达树

现在,如何执行这些表达式以及它们转向什么都取决于所谓的查询提供程序(表达式执行程序,我们可以认为它们)。

Entity Framework世界(这是神秘的底层数据源提供程序或查询提供程序)中, IQueryable表达式被转换为本机T-SQL查询。 Nhibernate与他们做类似的事情。 您可以按照LINQ:构建IQueryable Provider链接中描述的概念编写自己的概念,并且您可能希望为产品存储提供程序服务提供自定义查询API。

所以基本上, IQueryable对象一直在构建,直到我们显式释放它们并告诉系统将它们重写为SQL或其他任何东西并向下发送执行链以进行后续处理。

好像要延迟执行它是一个LINQ功能,用于在内存中保存表达式树方案,并且只有在需要对序列调用某些API(相同的Count,ToList等)时才将其发送到执行中。

两者的正确使用在很大程度上取决于您针对特定案例所面临的任务。 对于众所周知的存储库模式,我个人选择返回IList ,即IEnumerable over Lists(索引器等)。 因此,我的建议是仅在存储库中使用IQueryable ,并在代码中的任何其他地方使用IEnumerable。 没有说可IQueryable性问题, IQueryable崩溃和破坏关注分离原则。 如果从存储库中返回表达式,则消费者可以按照自己的意愿使用持久层。

混乱的一点点:)(来自评论中的讨论))它们都不是内存中的对象,因为它们本身并不是真正的类型,它们是一种类型的标记 - 如果你想深入了解它。 但是,将MSnumerables视为内存中的集合而将IQueryables视为表达式树,这是有意义的(这就是为什么即使是MSDN也这样说)。 关键是IQueryable接口继承IEnumerable接口,因此如果它表示查询,则可以枚举该查询的结果。 枚举导致与IQueryable对象关联的表达式树被执行。 所以,事实上,如果没有内存中的对象,你就无法真正调用任何IEnumerable成员。 如果你这样做,它会进入那里,无论如何,如果它不是空的。 IQueryables只是查询,而不是数据。

本文转载自:https://stackoom.com/question/C4L2/返回IEnumerable-T-与IQueryable相比-T-关闭

粉丝 0
博文 833
码字总数 0
作品 0
深圳
高级程序员
私信 提问
.NET深入解析LINQ框架(四:IQueryable、IQueryProvider接口详解)

阅读目录: 1.开篇介绍 2.扩展Linq to Object (应用框架具有查询功能) 2.1.通过添加IEnumerable对象的扩展方法 2.2.通过继承IEnumerable接口 2.3.详细的对象结构图 3.实现IQueryable 、IQuer...

王清培
2012/12/11
0
0
编写高质量代码改善C#程序的157个建议[IEnumerable和IQueryable、LINQ避免迭代、LINQ替代迭代]

前言 本文已更新至http://www.cnblogs.com/aehyok/p/3624579.html 。本文主要学习记录以下内容:   建议29、区别LINQ查询中的IEnumerable和IQueryable   建议30、使用LINQ取代集合中的比...

aehyok
2014/05/09
0
0
将不确定变为确定~DAL层向BLL层返回数据用IEnumerable还是IQueryable

DAL层从数据库中将数据读出来后,传递给BLL层,再通过BLL处理数据后,向WEB层返回,最后到页面上输出,这是一个过程,在这个过程中我需要说两句,BLL层与WEB层通讯肯定是List,IList等等...

mcy247
2017/12/05
0
0
IList,ICollection,IEnumerable,IEnumerator,IQueryable

IList 是 ICollection 接口的子代,并且是所有非泛型列表的基接口。IList 实现有三种类别:只读、固定大小和可变大小。无法修改只读 IList。固定大小的 IList 不允许添加或移除元素,但允许修...

随智阔
2012/08/08
398
0
.NET深入解析LINQ框架(三:LINQ优雅的前奏)

阅读目录: 1.动态LINQ查询(动态构建Expression表达式树) 2.DLR动态语言运行时(基于CLR之上的动态语言运行时) 1】.动态LINQ查询(动态构建Expression表达式树) 什么是动态LINQ查询?LINQ的编写...

王清培
2012/12/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

每天AC系列(六):有效的括号

1 题目 LeetCode第20题,这题比较简单,匹配括号. 2 栈 这是栈的典型应用,括号匹配,当然不需要直接使用栈,使用一个StringBuilder即可: if(s.isEmpty()) return true;char a = s.charAt(0);...

Blueeeeeee
今天
27
0
Spring AOP-06-切入点类型

切入点是匹配连接点的拦截规则。之前使用的是注解@Pointcut,该注解是AspectJ中的。除了这个注解之外,Spring也提供了其他一些切入点类型: • 静态方法切入点StaticMethodMatcherPointcut •...

moon888
昨天
90
0
Class Loaders in Java

1. Introduction to Class Loaders Class loaders are responsible for loading Java classes during runtime dynamically to the JVM (Java Virtual Machine). Also, they are part of the ......

Ciet
昨天
96
0
以Lazada为例,看电商系统架构演进

什么是Lazada? Lazada 2012年成立于新加坡,是东南亚第一电商,2016年阿里投资10亿美金,2017年完成对lazada的收购。 业务模式上Lazada更偏重自营,类似于亚马逊,自建仓储和为商家提供服务...

春哥大魔王的博客
昨天
62
0
【自用】 Flutter Timer 简单用法

dart: void _startTime() async { _timer = Timer(Duration(seconds: sec), () { fun(xxx,yyy,zzz); }); } @override void dispose() { _timer.cancel()......

Tensor丨思悟
昨天
65
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部