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. 考虑可读性:复杂查询适当分段或使用注释

相关推荐
pride.li3 小时前
开发板和Linux--nfs服务挂载
linux·运维·服务器
looking_for__3 小时前
【Linux】应用层协议
linux·服务器·网络
云泽8085 小时前
不止是命令:Linux 高频指令实战 + 芯片架构底层逻辑
linux·运维·服务器
j_xxx404_5 小时前
Linux:基础IO
linux·运维·服务器
Trouvaille ~7 小时前
【Linux】网络编程基础(二):数据封装与网络传输流程
linux·运维·服务器·网络·c++·tcp/ip·通信
万邦科技Lafite7 小时前
一键获取京东商品评论信息,item_reviewAPI接口指南
java·服务器·数据库·开放api·淘宝开放平台·京东开放平台
Trouvaille ~8 小时前
【Linux】网络编程基础(三):Socket编程预备知识
linux·运维·服务器·网络·c++·socket·网络字节序
德迅云安全—珍珍9 小时前
低配服务器性能不够用怎么去优化?
运维·服务器
笑锝没心没肺9 小时前
Linux Audit 系统配置介绍
linux·运维·服务器
REDcker9 小时前
RTSP 直播技术详解
linux·服务器·网络·音视频·实时音视频·直播·rtsp