LINQ语法

LINQ概述

LINQ (Language Integrated Query) 是.NET Framework的一项功能,它允许在C#和VB.NET中直接编写查询,用于查询各种数据源。

基本结构
csharp 复制代码
from item in dataSource
where condition
select item;

查询语法 vs 方法语法

查询语法 (Query Syntax)

更接近SQL,可读性更强

csharp 复制代码
// 示例:查询偶数
var numbers = new int[] { 1, 2, 3, 4, 5, 6 };
var evenNumbers = from num in numbers
                  where num % 2 == 0
                  select num;
// 结果: [2, 4, 6]
方法语法 (Method Syntax)

使用扩展方法和Lambda表达式,更灵活

csharp 复制代码
var evenNumbers = numbers.Where(num => num % 2 == 0);
// 结果: [2, 4, 6]

标准查询操作符

1. 筛选操作符 (Filtering)

Where - 根据条件筛选

csharp 复制代码
// 查询语法
var result = from p in products
             where p.Price > 100
             select p;

// 方法语法
var result = products.Where(p => p.Price > 100);

OfType - 根据类型筛选

csharp 复制代码
object[] objects = { 1, "hello", 2, "world", 3.14 };
var strings = objects.OfType<string>();
// 结果: ["hello", "world"]
2. 投影操作符 (Projection)

Select - 选择/转换元素

csharp 复制代码
// 查询语法
var names = from p in products
            select p.Name;

// 方法语法
var names = products.Select(p => p.Name);

SelectMany - 展平嵌套集合

csharp 复制代码
class Student {
    public List<string> Courses { get; set; }
}

var students = new List<Student> { /* ... */ };
var allCourses = students.SelectMany(s => s.Courses);
3. 排序操作符 (Ordering)

OrderBy / OrderByDescending - 升序/降序排序

csharp 复制代码
// 查询语法
var sorted = from p in products
             orderby p.Price descending
             select p;

// 方法语法
var sorted = products.OrderBy(p => p.Price);
var sortedDesc = products.OrderByDescending(p => p.Price);

ThenBy / ThenByDescending - 次要排序

csharp 复制代码
var sorted = products
    .OrderBy(p => p.Category)
    .ThenByDescending(p => p.Price);
4. 分组操作符 (Grouping)

GroupBy - 分组数据

csharp 复制代码
// 查询语法
var grouped = from p in products
              group p by p.Category into g
              select new { Category = g.Key, Products = g };

// 方法语法
var grouped = products.GroupBy(p => p.Category);

ToLookup - 创建查找表(立即执行)

csharp 复制代码
var lookup = products.ToLookup(p => p.Category);
var electronics = lookup["Electronics"];
5. 连接操作符 (Joining)

Join - 内连接

csharp 复制代码
var students = new List<Student> { /* ... */ };
var courses = new List<Course> { /* ... */ };

// 查询语法
var query = from s in students
            join c in courses on s.CourseId equals c.Id
            select new { s.Name, c.CourseName };

// 方法语法
var query = students.Join(courses,
    s => s.CourseId,
    c => c.Id,
    (s, c) => new { s.Name, c.CourseName });

GroupJoin - 分组连接

csharp 复制代码
var query = from c in categories
            join p in products on c.Id equals p.CategoryId into productGroup
            select new { Category = c.Name, Products = productGroup };

Zip - 合并两个序列

csharp 复制代码
var numbers = new[] { 1, 2, 3 };
var words = new[] { "one", "two", "three" };
var result = numbers.Zip(words, (n, w) => $"{n}: {w}");
// 结果: ["1: one", "2: two", "3: three"]
6. 集合操作符 (Set Operations)

Distinct - 去重

csharp 复制代码
int[] numbers = { 1, 2, 2, 3, 3, 3, 4 };
var unique = numbers.Distinct();
// 结果: [1, 2, 3, 4]

Union - 并集

csharp 复制代码
var list1 = new[] { 1, 2, 3 };
var list2 = new[] { 3, 4, 5 };
var union = list1.Union(list2);
// 结果: [1, 2, 3, 4, 5]

Intersect - 交集

csharp 复制代码
var intersect = list1.Intersect(list2);
// 结果: [3]

Except - 差集

csharp 复制代码
var except = list1.Except(list2);
// 结果: [1, 2]
7. 分区操作符 (Partitioning)

Skip / Take - 跳过/获取指定数量元素

csharp 复制代码
var page2 = products.Skip(10).Take(10); // 获取第2页,每页10条

SkipWhile / TakeWhile - 条件跳过/获取

csharp 复制代码
int[] numbers = { 1, 3, 5, 2, 4, 6 };
var result = numbers.SkipWhile(n => n < 4);
// 结果: [5, 2, 4, 6]
8. 聚合操作符 (Aggregation)

Count / LongCount - 计数

csharp 复制代码
int count = products.Count();
int expensiveCount = products.Count(p => p.Price > 100);

Sum / Average / Min / Max - 统计

csharp 复制代码
var total = products.Sum(p => p.Price);
var average = products.Average(p => p.Price);
var minPrice = products.Min(p => p.Price);
var maxPrice = products.Max(p => p.Price);

Aggregate - 自定义聚合

csharp 复制代码
int[] numbers = { 1, 2, 3, 4, 5 };
int product = numbers.Aggregate(1, (acc, n) => acc * n);
// 结果: 120 (1*2*3*4*5)
9. 元素操作符 (Element Operators)

First / FirstOrDefault - 获取第一个元素

csharp 复制代码
var first = products.First();
var firstOrDefault = products.FirstOrDefault(p => p.Price > 1000);

Last / LastOrDefault - 获取最后一个元素

csharp 复制代码
var last = products.Last();

Single / SingleOrDefault - 获取唯一元素

csharp 复制代码
var single = products.Single(p => p.Id == 1);

ElementAt / ElementAtOrDefault - 获取指定位置元素

csharp 复制代码
var third = products.ElementAt(2);
10. 转换操作符 (Conversion)

ToArray / ToList - 转换为数组/列表

csharp 复制代码
List<Product> productList = products.ToList();
Product[] productArray = products.ToArray();

ToDictionary - 转换为字典

csharp 复制代码
var dict = products.ToDictionary(p => p.Id, p => p.Name);

Cast - 强制类型转换

csharp 复制代码
ArrayList list = new ArrayList { 1, 2, 3 };
var ints = list.Cast<int>();

AsEnumerable / AsQueryable - 转换为可枚举/可查询

csharp 复制代码
var enumerable = products.AsEnumerable();
var queryable = products.AsQueryable();
11. 生成操作符 (Generation)

Range - 生成数字序列

csharp 复制代码
var numbers = Enumerable.Range(1, 10);
// 结果: [1, 2, 3, ..., 10]

Repeat - 重复元素

csharp 复制代码
var repeated = Enumerable.Repeat("Hello", 3);
// 结果: ["Hello", "Hello", "Hello"]

Empty - 空序列

csharp 复制代码
var empty = Enumerable.Empty<int>();
12. 相等性操作符 (Equality)

SequenceEqual - 序列相等比较

csharp 复制代码
var list1 = new[] { 1, 2, 3 };
var list2 = new[] { 1, 2, 3 };
bool equal = list1.SequenceEqual(list2); // true
13. 量词操作符 (Quantifiers)

Any - 是否存在满足条件的元素

csharp 复制代码
bool hasExpensive = products.Any(p => p.Price > 1000);
bool hasProducts = products.Any(); // 检查是否非空

All - 是否所有元素都满足条件

csharp 复制代码
bool allPositive = numbers.All(n => n > 0);

Contains - 是否包含指定元素

csharp 复制代码
bool hasProduct = products.Contains(specificProduct);

延迟执行与立即执行

延迟执行 (Deferred Execution)

查询不会立即执行,只有在遍历结果时才会执行

csharp 复制代码
var query = products.Where(p => p.Price > 100); // 未执行
foreach (var p in query) // 此时执行
{
    Console.WriteLine(p.Name);
}
立即执行 (Immediate Execution)

使用聚合方法或转换方法会立即执行

csharp 复制代码
List<Product> list = products.Where(p => p.Price > 100).ToList(); // 立即执行
int count = products.Count(); // 立即执行

LINQ to Objects小栗子

完整示例:学生成绩查询

csharp 复制代码
public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public List<CourseGrade> Grades { get; set; }
}

public class CourseGrade
{
    public string CourseName { get; set; }
    public int Score { get; set; }
}

// 数据准备
var students = new List<Student>
{
    new Student { Id = 1, Name = "Alice", Age = 20, Grades = new List<CourseGrade>
        { new CourseGrade { CourseName = "Math", Score = 85 }, new CourseGrade { CourseName = "English", Score = 90 } } },
    new Student { Id = 2, Name = "Bob", Age = 21, Grades = new List<CourseGrade>
        { new CourseGrade { CourseName = "Math", Score = 78 }, new CourseGrade { CourseName = "English", Score = 82 } } },
    new Student { Id = 3, Name = "Charlie", Age = 19, Grades = new List<CourseGrade>
        { new CourseGrade { CourseName = "Math", Score = 92 }, new CourseGrade { CourseName = "English", Score = 88 } } }
};

// 复杂查询示例
var query = from s in students
            where s.Age >= 20
            from g in s.Grades
            where g.Score >= 80
            group g by s.Name into studentGrades
            select new
            {
                StudentName = studentGrades.Key,
                AverageScore = studentGrades.Average(g => g.Score),
                HighScore = studentGrades.Max(g => g.Score)
            };

// 方法语法等价写法
var query2 = students
    .Where(s => s.Age >= 20)
    .SelectMany(s => s.Grades
        .Where(g => g.Score >= 80)
        .Select(g => new { Student = s, Grade = g }))
    .GroupBy(x => x.Student.Name)
    .Select(g => new
    {
        StudentName = g.Key,
        AverageScore = g.Average(x => x.Grade.Score),
        HighScore = g.Max(x => x.Grade.Score)
    });

LINQ to SQL/Entity Framework

基本查询
csharp 复制代码
using (var context = new SchoolContext())
{
    // 查询语法
    var query = from s in context.Students
                where s.EnrollmentDate.Year == 2020
                orderby s.LastName
                select new { s.FirstName, s.LastName, s.EnrollmentDate };
    
    // 方法语法
    var query2 = context.Students
        .Where(s => s.EnrollmentDate.Year == 2020)
        .OrderBy(s => s.LastName)
        .Select(s => new { s.FirstName, s.LastName, s.EnrollmentDate });
    
    // 注意:延迟执行,实际SQL在遍历时生成
    foreach (var student in query)
    {
        Console.WriteLine(student);
    }
}
连接查询
csharp 复制代码
var query = from s in context.Students
            join e in context.Enrollments on s.StudentId equals e.StudentId
            join c in context.Courses on e.CourseId equals c.CourseId
            select new { s.Name, c.Title, e.Grade };

进阶主题

1. 复合查询
csharp 复制代码
var complexQuery = 
    from p in products
    join c in categories on p.CategoryId equals c.Id
    where p.Price > 50 && c.IsActive
    group p by c.Name into g
    orderby g.Count() descending
    select new
    {
        Category = g.Key,
        TotalProducts = g.Count(),
        AveragePrice = g.Average(p => p.Price),
        Products = g.Select(p => p.Name)
    };
2. 动态查询
csharp 复制代码
IQueryable<Product> query = context.Products;

if (minPrice.HasValue)
    query = query.Where(p => p.Price >= minPrice.Value);
    
if (!string.IsNullOrEmpty(category))
    query = query.Where(p => p.Category == category);
    
if (sortByPrice)
    query = query.OrderBy(p => p.Price);
3. 性能优化技巧
csharp 复制代码
// 使用 AsNoTracking 提高只读查询性能
var products = context.Products.AsNoTracking().ToList();

// 使用 Select 只获取需要的字段
var names = context.Products.Select(p => p.Name).ToList();

// 批量操作时使用合适的批处理大小
context.BulkInsert(products, options => options.BatchSize = 1000);
4. 自定义扩展方法
csharp 复制代码
public static class LinqExtensions
{
    public static IEnumerable<T> WhereIf<T>(
        this IEnumerable<T> source, 
        bool condition, 
        Func<T, bool> predicate)
    {
        return condition ? source.Where(predicate) : source;
    }
}

// 使用
var result = products
    .WhereIf(minPrice.HasValue, p => p.Price >= minPrice.Value)
    .WhereIf(!string.IsNullOrEmpty(category), p => p.Category == category);

总结

操作类型 常用操作符 特点
筛选 Where, OfType 条件过滤数据
投影 Select, SelectMany 转换数据形状
排序 OrderBy, ThenBy 数据排序
分组 GroupBy, ToLookup 数据分组
连接 Join, GroupJoin 合并数据源
集合 Union, Intersect 集合运算
聚合 Count, Sum, Average 数据统计
元素 First, Single, ElementAt 获取特定元素
转换 ToList, ToArray, ToDictionary 转换结果类型

最佳实践建议

  1. 选择合适的语法:简单查询用查询语法,复杂操作用方法语法

  2. 注意性能:数据库查询时使用合适的索引,避免N+1查询问题

  3. 使用延迟执行优势:构建动态查询链

  4. 及时释放资源:数据库上下文及时Dispose

  5. 考虑可读性:复杂查询适当分段或使用注释

相关推荐
酉鬼女又兒4 小时前
零基础入门计算机网络:网络层核心任务、三大关键问题、两种服务类型与 TCP/IP 网际层协议体系全解析
服务器·网络·网络协议·tcp/ip·计算机网络·php·求职招聘
Gauss松鼠会5 小时前
【GaussDB】GaussDB重要通信参数汇总
服务器·网络·数据库·sql·性能优化·gaussdb·经验总结
凡人叶枫5 小时前
Effective C++ 条款10:令 operator= 返回一个 reference to *this
java·linux·服务器·开发语言·c++·effective c++
某林2125 小时前
Isaac Sim 5.1.0 无头服务器部署与 RTX 显存段错误排障全记录
运维·服务器·docker·容器·isaac
m0_738120725 小时前
Docker 环境下 Vulfocus 靶场搭建全流程(附镜像源问题解决方案)
运维·服务器·网络·安全·docker·容器
Gauss松鼠会6 小时前
【GaussDB】GaussDB SMP特性调优详解
java·服务器·前端·数据库·sql·算法·gaussdb
枫叶梨花6 小时前
Dify 离线安装 OpenAI API Compatible 插件踩坑记
服务器·人工智能
Yukinaaaa6 小时前
以“轮盘数组”思维彻底搞懂并实现阻塞队列
java·服务器·ide·安全·javaee·阻塞队列·轮盘数组
HLC++7 小时前
Linux文件操作
linux·运维·服务器
晚风予卿云月7 小时前
【Linux】进程控制(二)——进程等待 全方位详解
linux·运维·服务器·进程控制·进程等待