修身养性,知行合一

  • 首页
  • 爱码
    • 系统
    • 数据库
    • JavaScript
    • CSharp
    • Python
  • 生活
    • 文化
    • 美食
  • 杂谈
  • 关于
修身养性,知行合一
码字,杂谈
  1. 首页
  2. 爱码
  3. CSharp
  4. ASP.NET
  5. 正文

浅谈 IEnumerable 与 IQueryable 的区别

2021年8月20日 4011点热度 0人点赞 0条评论

开始之前

在写数据操作时,经常会与这两个接口打交道,它们有着几乎相同的方法,使用起来基本无二,甚至通过 As 方法可以相互转换。那么它们之间到底有什么区别,今天就聊聊这两个接口。

为了更好的理解,我们尝试使用如下语句进行理解:

IQueryable<Project> projects1 = Db.Where(x => x.Id == projectId);
IEnumerable<Project> projects2 = Db.Where(x => x.Id == projectId);

IEnumerable

IEnumerable 是 linq to object 的方式,它需要将所有原始匹配的对象加载到内存后,再进行查询。

那么 projects1 在查询时仅仅执行数据库中的原始查询,将 Db 的所有数据都加载到内存中,然后通过 Where 过滤掉不需要的数据。

使用 IEnumerable 会大量消耗内存,虽然我们一般理解内存处理数据很快,但是相比于 sql 来说,它慢的一批。

IQueryable

IQueryable 则是 linq to sql 的方式,它会将所有查询整合为一整条 sql,这得益于强大的表达式树。

所以 projects2 仅仅是从数据库中查询符合条件的数据,效率明显要比 IEnumerable 要高。

印证

为了印证它们的不同,我们可以分别看一下两者的 Where 方法的参数:

// IQueryable
Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)

// IEnumerable
Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)

IQueryable 方法的参数都是 Expression,而 IEnumerable 方法的参数是一个 Func。通过这两个参数,已经可以窥见它们的编译方式的不同。

IQueryable 会将所有查询编译为一个表达式树,然后转为 sql。

而 IEnumerable 只是在需要查询的地方调用函数而已。

这也是 IQueryable 通常比 IEnumerable 查询速度更快的原因。

何时使用它们

当然,这也并不代表我们可以随便替换它们。我们不可以为了提高速度而将 IEnumerable 转化为 IQueryable 进行查询,这并不会有任何好处。

针对何时使用它们,我们需要根据基础数据源:

  • 查询数据库时,或者编写查询执行之前的扩展时,可以使用 IQueryable
  • 查询一组已经存在在内存中的数据时,可以使用 IEnumerable

整体来说,我们一般可以通过使用 var 而非特定的 IQueryable<> 或者 IEnumerable<>,系统将帮助我们自动判定类型。

延迟查询

这两个接口都可以延迟查询。

所谓延迟查询,就是查询的执行被退出,知道查询变量在循环中迭代,这就是延迟查询。

根据这个特性,我们可以在数据后面编写多个查询语句,当遇到循环或者通过一些立即执行方法的时候,才会开始执行真正的查询。

如要强制立即执行,可以通过对查询变量调用 ToList、ToArray 等方法,可以理解执行并序列为对应格式的数据。

使用上的相同

虽然在使用上感觉不到太大差别,但是它的内部还是有很大差别,比如 Where 的部分源码如下:

// IQueryable
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
{
    return source.Provider.CreateQuery<TSource>(
        Expression.Call(
            null,
            CachedReflectionInfo.Where_TSource_2(typeof(TSource)),
            source.Expression, Expression.Quote(predicate)
            ));
}

// IEnumerable
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source is Iterator<TSource> iterator) return iterator.Where(predicate);

    if (source is TSource[] array)
        return array.Length == 0 ?
            Empty<TSource>() :
            new WhereArrayIterator<TSource>(array, predicate);

    if (source is List<TSource> list) return new WhereListIterator<TSource>(list, predicate);

    return new WhereEnumerableIterator<TSource>(source, predicate);
}

我觉得所谓的使用相同,更多是巨硬为了让开发者减少学习成本而刻意为之,仅此而已。当然,这也是 C# 好用的一大特点。

最后

记住两者最根本的区别,两者不要随意转换。只有查询基础数据(数据库)时,IQueryable 才更有用,把一个普通可迭代对象通过 AsQueryable 转换并没有什么实际意义。

最后放一张图,网上看到的,还不错,言简意赅。

file

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: csharp
最后更新:2021年8月20日

jeremyjone

这个人很懒,什么都没留下

打赏 点赞
< 上一篇
下一篇 >

文章评论

取消回复

文章目录
  • 开始之前
  • IEnumerable
  • IQueryable
  • 印证
  • 何时使用它们
  • 延迟查询
  • 使用上的相同
  • 最后
最新 热点 随机
最新 热点 随机
node-sass 的安装 解决端口被占的问题 vue3 组件 Props 的声明方式 给 div 添加选中状态 请求的取消 rgb 颜色小数兼容问题
node-sass 的安装
关于 *.vue 文件中使用 TypeScript 声明类型报错的解决方案 windows下添加右键菜单并打开文件 Vim使用指南 iOS 正则匹配问题 MongoDB安装后允许其他IP访问的方法 vscode 收起多余的配置文件

(っ•̀ω•́)っ✎⁾⁾ 开心每一天

COPYRIGHT © 2021 jeremyjone.com. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

京ICP备19012859号-1

京公网安备 11010802028585号