导读:本期聚焦于小伙伴创作的《C#中Enumerable和Queryable的区别是什么?C# LINQ两种查询模式对比解析》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#中Enumerable和Queryable的区别是什么?C# LINQ两种查询模式对比解析》有用,将其分享出去将是对创作者最好的鼓励。

在C#的LINQ技术体系中,Enumerable和Queryable是两个核心的静态类,分别对应本地数据查询和远程数据查询两种模式,很多开发者在初学或者面试时都会遇到两者的区别相关问题,理解它们的差异对写出高效的查询代码非常重要。

Enumerable和Queryable的基本定义

Enumerable类位于System.Linq命名空间下,它的扩展方法主要针对实现了IEnumerable<T>接口的数据源,比如内存中的集合、数组等本地数据。而Queryable类同样位于System.Linq命名空间下,它的扩展方法针对实现了IQueryable<T>接口的数据源,最常见的就是ORM框架中的数据库查询对象,比如Entity Framework的DbSet。

核心差异对比

执行方式差异

Enumerable的查询是在内存中执行的,它会把所有的查询操作编译成委托,在触发执行的时候遍历本地数据源,逐个执行委托逻辑。而Queryable的查询会把LINQ表达式转换成表达式树,最终由具体的提供程序(比如数据库提供程序)把表达式树转换成对应的查询语句(比如SQL语句)发送到远程数据源执行。

延迟查询的表现差异

两者都支持延迟查询,也就是查询定义之后不会立即执行,只有枚举结果的时候才会触发执行,但延迟的实现逻辑不同。Enumerable的延迟是在本地内存中延迟枚举,而Queryable的延迟是把表达式树的构建延迟到最终执行的时候才转换成目标查询语句。

对比维度EnumerableQueryable
针对数据源本地内存数据(IEnumerable<T>)远程数据源(IQueryable<T>)
查询逻辑载体编译后的委托表达式树
最终执行位置本地进程内存远程数据源(如数据库服务器)
适用场景内存集合、数组等本地数据查询数据库、远程服务等数据源查询

代码示例对比

Enumerable查询示例

下面的代码演示了对内存中列表的查询,使用的是Enumerable的扩展方法:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // 本地内存中的用户列表
        List<User> userList = new List<User>
        {
            new User { Id = 1, Name = "张三", Age = 25 },
            new User { Id = 2, Name = "李四", Age = 30 },
            new User { Id = 3, Name = "王五", Age = 25 }
        };

        // 使用Enumerable的Where扩展方法,等价于LINQ查询语法
        var query = userList.Where(u => u.Age == 25);
        // 此时查询还未执行,只有枚举结果的时候才会触发
        foreach (var user in query)
        {
            Console.WriteLine($"Id:{user.Id}, Name:{user.Name}");
        }
    }
}

class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

Queryable查询示例

下面的代码演示了对数据库上下文的查询,使用的是Queryable的扩展方法,这里以Entity Framework的场景为例:

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;

class Program
{
    static void Main()
    {
        using (var dbContext = new TestDbContext())
        {
            // DbSet实现了IQueryable<T>接口,使用的是Queryable的扩展方法
            var query = dbContext.Users.Where(u => u.Age == 25);
            // 此时只是构建表达式树,不会发送SQL到数据库
            // 枚举结果的时候才会把表达式树转换成SQL执行查询
            foreach (var user in query)
            {
                Console.WriteLine($"Id:{user.Id}, Name:{user.Name}");
            }
        }
    }
}

// 数据库上下文和实体类定义
class TestDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // 示例连接字符串,实际使用时替换为真实配置
        optionsBuilder.UseSqlServer("Server=.;Database=TestDB;Trusted_Connection=True;");
    }
}

class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

常见面试问题梳理

  • 问:为什么对数据库查询使用Enumerable的扩展方法会导致性能问题?
    答:如果先把IQueryable数据源转换成IEnumerable(比如调用AsEnumerable()),那么后续的查询操作会使用Enumerable的扩展方法,原本可以在数据库端执行的过滤、排序等操作会被拿到内存中执行,导致查询大量冗余数据,性能下降。
  • 问:如何判断当前使用的是Enumerable还是Queryable的查询?
    答:看数据源的类型,如果数据源是IEnumerable<T>且没有实现IQueryable<T>,那么使用的是Enumerable的方法;如果数据源是IQueryable<T>,那么使用的是Queryable的方法,也可以通过查看生成的查询语句来判断,Queryable的查询会生成对应的远程查询语句。
  • 问:两者的延迟查询有什么不同?
    答:Enumerable的延迟是本地延迟枚举,所有数据已经在内存中,只是延迟遍历;Queryable的延迟是延迟把表达式树转换成目标查询语句,在枚举之前不会向远程数据源发送任何请求。

使用建议

在实际开发中,如果是操作内存中的本地集合、数组等数据,直接使用Enumerable相关的查询即可;如果是操作数据库、远程API等数据源,要确保数据源是IQueryable<T>类型,避免使用AsEnumerable()或者ToList()提前把数据加载到内存,尽量让查询操作在远程数据源端执行,减少数据传输和内存占用。如果需要对查询结果的本地处理,再在最后调用ToList()或者ToArray()把结果加载到内存中。

C#LINQEnumerableQueryable延迟查询修改时间:2026-06-22 20:21:50

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。