LINQ 表达式详解

1. 基础概念与用法

1.1 什么是 LINQ?

LINQ 是 .NET Framework 3.5 引入的一项特性,它将查询能力直接集成到 C# 语言中。通过 LINQ,你可以像写 SQL 一样对内存中的集合(如 List<T>、数组)或外部数据源(如数据库、XML)进行操作,而无需手动编写复杂的循环和条件判断。

关键优势

  • 语法简洁、可读性强
  • 编译时类型安全
  • 支持多种数据源(统一查询模型)
  • 支持延迟执行(性能优化)

1.2 LINQ 的两种语法形式

LINQ 支持两种写法:

  • 查询表达式语法(Query Syntax):类似 SQL,更直观
  • 方法语法(Method Syntax / Fluent Syntax):基于扩展方法,更灵活

两者功能等价,可根据习惯选择。初学者建议从查询表达式入手,进阶后多用方法语法。

1.3 常用 LINQ 方法(方法语法)

以下是最常用的核心 LINQ 方法(均定义在 System.Linq 命名空间中):

方法 说明
Where 筛选满足条件的元素
Select 投影(转换)每个元素
OrderBy / OrderByDescending 升序/降序排序
GroupBy 按键分组
Distinct 去重
Count 统计元素数量
First / FirstOrDefault 获取第一个元素(或默认值)
Any 判断是否存在满足条件的元素

💡 所有这些方法都是扩展方法,作用于实现了 IEnumerable<T> 接口的集合(如 List<T>、数组等)。

1.4 简单示例

示例 1:筛选偶数并排序(方法语法)

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

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        var evenNumbers = numbers
            .Where(n => n % 2 == 0)      // 筛选偶数
            .OrderBy(n => n);            // 升序排列

        foreach (var num in evenNumbers)
        {
            Console.WriteLine(num); // 输出:2, 4, 6, 8, 10
        }
    }
}

示例 2:查询表达式语法(等价写法)

var evenNumbers = from n in numbers
                  where n % 2 == 0
                  orderby n
                  select n;

注意

  • whereorderbyselect 是 C# 关键字,不是方法名
  • 查询表达式最终会被编译器转换为方法语法

示例 3:投影(Select)——提取对象属性

class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
}

var students = new List<Student>
{
    new Student { Name = "Alice", Age = 20 },
    new Student { Name = "Bob", Age = 22 }
};

// 只提取名字
var names = students.Select(s => s.Name).ToList();

foreach (var name in names)
{
    Console.WriteLine(name); // Alice, Bob
}

2. 进阶知识点

2.1 延迟执行(Deferred Execution)

LINQ 查询不会立即执行,而是在你遍历结果(如 foreachToList()Count())时才真正计算。

var query = numbers.Where(n => n > 5); // 此时未执行!
numbers.Add(100);                      // 修改原集合
var result = query.ToList();           // 此刻才执行,包含 100!

⚠️ 陷阱:如果在查询定义后修改了源集合,结果可能出乎意料。
建议:若需“快照”,立即调用 .ToList().ToArray()

2.2 立即执行 vs 延迟执行

延迟执行方法 立即执行方法
Where, Select, OrderBy ToList(), ToArray(), Count(), First(), Sum()

2.3 多条件查询与复合排序

var result = students
    .Where(s => s.Age > 18 && s.Name.StartsWith("A"))
    .OrderBy(s => s.Age)
    .ThenBy(s => s.Name); // 先按年龄,再按名字排序

2.4 分组(GroupBy)

var groups = students.GroupBy(s => s.Age);

foreach (var group in groups)
{
    Console.WriteLine($"Age {group.Key}:");
    foreach (var student in group)
    {
        Console.WriteLine($"  - {student.Name}");
    }
}

2.5 联合查询(Join)

模拟 SQL 的 JOIN,用于关联两个集合:

var orders = new List<Order> { /* ... */ };
var customers = new List<Customer> { /* ... */ };

var query = from c in customers
            join o in orders on c.Id equals o.CustomerId
            select new { c.Name, o.OrderDate };

2.6 聚合操作

LINQ 提供丰富的聚合函数:

int sum = numbers.Sum();
double avg = numbers.Average();
int max = numbers.Max();
bool anyAdult = students.Any(s => s.Age >= 18);

2.7 自定义比较器(IEqualityComparer)

Distinct()GroupBy() 中,可通过实现 IEqualityComparer<T> 控制“相等”逻辑。


3. 实际工作中的使用场景

场景 1:数据筛选与展示(Web API / 前端列表)

场景描述
在 Web 应用中,用户可能需要按条件筛选商品(如价格区间、品牌、库存状态)。

LINQ 应用

var filteredProducts = products
    .Where(p => p.Price >= minPrice && p.Price <= maxPrice)
    .Where(p => !string.IsNullOrEmpty(p.Brand))
    .Where(p => p.InStock)
    .OrderBy(p => p.Price)
    .Select(p => new ProductDto { Name = p.Name, Price = p.Price });

优势:代码清晰,易于维护,支持动态组合条件。


场景 2:日志分析(运维/监控)

场景描述
从大量日志记录中找出错误级别为 "Error" 且包含特定关键词的日志。

LINQ 应用

var errorLogs = logs
    .Where(log => log.Level == "Error")
    .Where(log => log.Message.Contains("Timeout"))
    .OrderByDescending(log => log.Timestamp)
    .Take(10); // 只取最近10条

优势:无需写多重 for 循环,逻辑一目了然。


场景 3:数据去重与合并(ETL / 数据清洗)

场景描述
从多个数据源导入用户信息,可能存在重复记录,需合并并去重。

LINQ 应用

var allUsers = source1.Union(source2) // 合并
                      .DistinctBy(u => u.Email) // 按邮箱去重(.NET 6+)
                      .ToList();

💡 若使用 .NET 6 以下版本,可用 GroupBy(u => u.Email).Select(g => g.First()) 实现类似效果。


场景 4:报表生成(统计与分组)

场景描述
生成销售报表,按月份统计订单数量和总金额。

LINQ 应用

var monthlyReport = orders
    .GroupBy(o => o.OrderDate.ToString("yyyy-MM"))
    .Select(g => new
    {
        Month = g.Key,
        OrderCount = g.Count(),
        TotalAmount = g.Sum(o => o.Amount)
    })
    .OrderBy(r => r.Month);

优势:一行代码完成分组+聚合,替代传统 Dictionary 手动累加。


场景 5:配置验证(系统初始化)

场景描述
检查配置文件中是否存在重复的键或无效值。

LINQ 应用

bool hasDuplicateKeys = configItems
    .GroupBy(item => item.Key)
    .Any(g => g.Count() > 1);

bool hasInvalidValues = configItems
    .Any(item => string.IsNullOrWhiteSpace(item.Value));

优势:快速验证,提升系统健壮性。


总结

LINQ 是 C# 开发者必须掌握的核心技能之一。它不仅简化了集合操作,还提升了代码的可读性与可维护性。作为初学者,建议:

  1. 先掌握常用方法WhereSelectOrderByGroupBy
  2. 理解延迟执行机制,避免常见陷阱
  3. 在实际项目中多练习,如处理列表、过滤数据、生成报表等
  4. 结合 IDE 智能提示(如 Visual Studio 的自动补全)快速熟悉方法链

🌟 记住:LINQ 不是“炫技”,而是让代码更接近人类思维的工具。用好 LINQ,你的 C# 代码将更加优雅、高效!


📌 提示:所有示例均需在文件顶部添加 using System.Linq;
📌 推荐练习:尝试将你项目中的 foreach + if 逻辑改写为 LINQ 表达式,感受其简洁之美!

posted @ 2025-11-01 16:35  恨水长秋  阅读(76)  评论(0)    收藏  举报