C# 如何使用 LINQ 查询数据?常用 LINQ 数据查询技巧详解

来源:Nodejs社区作者:深圳网站建设头衔:草根站长
导读:本期聚焦于深圳网站建设创作的《C# 如何使用 LINQ 查询数据?常用 LINQ 数据查询技巧详解》,敬请观看详情。LINQ 是 C# 中非常强大的数据查询工具,它用统一的语法查询集合、数据库、XML 等多种数据源。本文将系统讲解 LINQ 的基本用法和进阶技巧,包括查询语法与方法语法的区别、Where 与 Select 的筛选投影、排序分组、聚合统计以及延迟执行原理等内容。通过大量可直接运行的代码示例,帮助你快速掌握用 LINQ 简化日常开发中的数据处理逻辑,写出更简洁、更易维护的 C# 代码。

在 C# 开发中,数据处理占据了大量工作。过去我们需要手写循环、条件判断来筛选和转换集合数据,代码冗长且容易出错。LINQ(Language Integrated Query,语言集成查询)的出现彻底改变了这一局面,它让我们能够用类似 SQL 的声明式语法,对集合、数组、数据库、XML 等多种数据源进行统一查询。掌握 LINQ 不仅能让代码更简洁,还能显著提升开发效率。本文将从基础语法讲到进阶技巧,配合丰富的代码示例,带你全面掌握 C# 中的 LINQ 数据查询。

C# 如何使用 LINQ 查询数据?常用 LINQ 数据查询技巧详解

一、LINQ 的两种查询语法:查询语法与方法语法

LINQ 提供两种写法:查询语法(Query Syntax)和方法语法(Method Syntax)。查询语法更接近 SQL,可读性好;方法语法基于扩展方法和 Lambda 表达式,功能更全面(部分操作符如 CountFirst 只有方法形式)。两种语法可以混用,编译后生成的代码完全相同。

int[] numbers = { 5, 2, 8, 1, 9, 3 };

// 查询语法
var query1 = from n in numbers
             where n > 3
             select n;

// 方法语法(效果等价)
var query2 = numbers.Where(n => n > 3);

foreach (var n in query1)
{
    Console.WriteLine(n); // 输出 5 8 9
}

初学者建议先从查询语法入手理解思路,实际项目中方法语法使用更普遍,因为可以链式调用,且不受操作符覆盖范围的限制。两者没有性能差异,选择哪一种主要看团队习惯和代码可读性。

二、筛选、投影与排序:Where、Select、OrderBy

这是 LINQ 最常用的三个操作。Where 用于按条件筛选元素,Select 用于把元素投影成新形态(类似 SQL 的 SELECT 列),OrderBy / OrderByDescending 用于排序,还可以用 ThenBy 实现多级排序。

var students = new[]
{
    new { Name = "张三", Age = 20, Score = 85 },
    new { Name = "李四", Age = 22, Score = 92 },
    new { Name = "王五", Age = 20, Score = 78 }
};

var result = students
    .Where(s => s.Score >= 80)          // 筛选成绩合格的学生
    .OrderByDescending(s => s.Score)     // 按成绩降序
    .ThenBy(s => s.Age)                  // 成绩相同时按年龄升序
    .Select(s => new { s.Name, s.Score }); // 只取需要的字段

foreach (var s in result)
{
    Console.WriteLine($"{s.Name}: {s.Score}");
}

需要注意 Select 投影成匿名类型后,返回的结果类型与原集合不同,这在只关心部分字段时可以减少内存占用。此外,Where 可以串联多次,多个条件会依次过滤,等价于逻辑与的关系。

三、分组与聚合:GroupBy、Count、Sum、Average

分组统计是数据处理的高频需求。GroupBy 按指定的键将元素分组,每组是一个实现了 IGrouping 接口的对象,包含键值和元素序列;配合 CountSumAverageMaxMin 等聚合操作符,可以轻松完成报表类统计。

var orders = new[]
{
    new { Product = "手机", Category = "数码", Amount = 4999 },
    new { Product = "耳机", Category = "数码", Amount = 399 },
    new { Product = "外套", Category = "服装", Amount = 299 },
    new { Product = "裤子", Category = "服装", Amount = 199 }
};

var statistics = orders
    .GroupBy(o => o.Category)
    .Select(g => new
    {
        Category = g.Key,      // 分组的键
        Count = g.Count(),     // 每组订单数
        Total = g.Sum(o => o.Amount)  // 每组总金额
    });

foreach (var s in statistics)
{
    Console.WriteLine($"{s.Category}: {s.Count} 单,合计 {s.Total} 元");
}

如果想按多个字段分组,可以用匿名类型作为键:GroupBy(o => new { o.Category, o.Product })。聚合操作符都有带种子值的重载,例如 Aggregate 可以实现自定义累积逻辑,适合求字符串拼接等复杂场景。

四、连接查询与集合操作:Join、Distinct、Union

当需要关联两个数据源时,可以使用 Join,它类似 SQL 的内连接;GroupJoin 则可以实现一对多的分组连接。集合运算方面,Distinct 去重、Union 并集、Intersect 交集、Except 差集也非常实用。

var departments = new[]
{
    new { Id = 1, Name = "技术部" },
    new { Id = 2, Name = "市场部" }
};

var employees = new[]
{
    new { Name = "张三", DeptId = 1 },
    new { Name = "李四", DeptId = 2 },
    new { Name = "王五", DeptId = 1 }
};

// 内连接:员工与部门关联
var joined = employees.Join(departments,
    e => e.DeptId,
    d => d.Id,
    (e, d) => new { e.Name, DeptName = d.Name });

int[] a = { 1, 2, 3, 3 };
int[] b = { 3, 4, 5 };

var distinct = a.Distinct();        // 1 2 3
var union = a.Union(b);             // 1 2 3 4 5(自动去重)
var intersect = a.Intersect(b);     // 3
var except = a.Except(b);           // 1 2

使用 Join 时要特别注意两个键的选择器类型必须一致,否则编译不报错但运行时关联不上。UnionConcat 的区别在于前者会去重,后者只是简单拼接。

五、理解延迟执行:LINQ 最容易踩的坑

LINQ 查询默认是延迟执行的(Deferred Execution),即定义查询时并不执行,只有在遍历结果(如 foreach)或调用 ToListCount 等方法时才真正执行。这是 LINQ 的核心设计,好处是可以组合多个查询而不产生中间集合,但也容易引发问题。

var list = new List<int> { 1, 2, 3 };
var query = list.Where(n => n > 1);

list.Add(4);

foreach (var n in query)
{
    Console.WriteLine(n); // 输出 2 3 4,包含后添加的元素
}

// 如果希望立即固定结果,使用 ToList
var fixedList = list.Where(n => n > 1).ToList();

延迟执行的另一个陷阱是多次遍历同一个查询会导致重复计算,比如先 Count()foreach,数据源会被枚举两次。如果数据源是数据库,还可能发起两次 SQL 查询。解决办法是在需要复用结果时调用 ToList()ToArray() 物化结果。另外要注意,遍历查询时如果修改了集合,会抛出 InvalidOperationException 异常。

六、实用技巧与性能建议

掌握以下技巧可以让你把 LINQ 用得更加得心应手:

  • 善用 Any 替代 Count() > 0Any() 找到第一个匹配元素就返回,不需要遍历整个集合,性能更好。
  • 空值防护:对可能为 null 的集合使用 ?? Enumerable.Empty<T>(),避免空引用异常。
  • FirstFirstOrDefault 的选择:确定必须有结果时用 First(无结果抛异常),不确定时用 FirstOrDefault(返回默认值)。
  • ToDictionary 快速建索引:需要频繁按键查找时,先把列表转成字典,查找复杂度从 O(n) 降为 O(1)。
  • 注意 IEnumerable 与 IQueryable 的区别:操作数据库时(如 EF Core),确保查询保持 IQueryable 类型,筛选条件才能被翻译成 SQL 在数据库端执行;过早调用 AsEnumerableToList 会把全部数据加载到内存再过滤。

总的来说,LINQ 是 C# 开发者必须熟练掌握的技能。建议从 WhereSelectOrderBy 这几个高频操作练起,逐步过渡到分组、连接和延迟执行等进阶概念。写 LINQ 时始终记住它是声明式的,描述的是“要什么”而不是“怎么做”,思维方式的转变会让你的代码质量提升一个台阶。

C# LINQLINQ查询数据查询技巧修改时间:2026-09-02 07:06:32

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