[转载]C# LINQ 快速入门实战指南,建议收藏学习!

LINQ介绍

LINQ语言集成查询是一系列直接将查询功能集成到 C# 语言的技术统称。数据查询历来都表示为简单的字符串,没有编译时类型检查或 IntelliSense 支持。此外,需要针对每种类型的数据源了解不同的查询语言:SQL 数据库、XML 文档、各种 Web 服务等。然而,LINQ的出现改变了这一现状,它使查询成为了与类、方法和事件同等重要的高级语言构造。通过LINQ,开发者能够以声明性的方式查询和操作数据,极大地提高了开发效率和代码的可维护性。

LINQ具有以下特性

  • 强类型:编译时验证查询逻辑,减少运行时错误。
  • 延迟执行:LINQ查询通常是延迟执行的,即查询表达式本身不会立即执行,直到实际遍历结果时才触发查询。使用 ToList()ToArray()ToDictionary()FirstOrDefault()等方法可立即执行。
  • 支持多种数据源:LINQ可以用于查询多种数据源,如LINQ to Objects、LINQ to XML、LINQ to SQL、LINQ to Entities(Entity Framework)等。
  • LINQ中常用方法

    操作示例数据

 1         public class StudentInfo
 2         {
 3             public int StudentID { get; set; }
 4             public string StudentName { get; set; }
 5             public DateTime Birthday { get; set; }
 6             public int ClassID { get; set; }
 7             public string Address { get; set; }
 8             public List<Course> Courses { get; set; } = new List<Course>();
 9         }
10 
11         public class Course
12         {
13             public int CourseID { get; set; }
14             public string CourseName { get; set; }
15         }
16 
17         static List<StudentInfo> students = new List<StudentInfo>
18         {
19             new StudentInfo
20             {
21                 StudentID=1,
22                 StudentName="大姚",
23                 Birthday=Convert.ToDateTime("1997-10-25"),
24                 ClassID=101,
25                 Courses = new List<Course>
26                 {
27                     new Course { CourseID = 101, CourseName = "语文" },
28                     new Course { CourseID = 102, CourseName = "数学" }
29                 }
30             },
31             new StudentInfo
32             {
33                 StudentID=2,
34                 StudentName="李四",
35                 Birthday=Convert.ToDateTime("1998-10-25"),
36                 ClassID=101,
37                 Courses = new List<Course>
38                 {
39                     new Course { CourseID = 101, CourseName = "语文" },
40                     new Course { CourseID = 102, CourseName = "数学" }
41                 }
42             },
43             new StudentInfo
44             {
45                 StudentID=3,
46                 StudentName="王五",
47                 Birthday=Convert.ToDateTime("1999-10-25"),
48                 ClassID=102,
49                 Address="广州",
50                 Courses = new List<Course>
51                 {
52                     new Course { CourseID = 101, CourseName = "语文" },
53                     new Course { CourseID = 102, CourseName = "数学" }
54                 }
55             },
56             new StudentInfo
57             {
58                 StudentID=4,
59                 StudentName="时光者",
60                 Birthday=Convert.ToDateTime("1999-11-25"),
61                 ClassID=102,
62                 Address="深圳" ,
63                 Courses = new List<Course>
64                 {
65                     new Course { CourseID = 104, CourseName = "历史" },
66                     new Course { CourseID = 103, CourseName = "地理" }
67                 }
68             }
69         };
View Code

 

基本查询方法

  • Where:用于过滤集合中的元素,通过一个谓词(返回布尔值的条件)筛选集合中的元素,生成一个仅包含满足条件元素的新序列。
  • Select:用于将集合中的每个元素投影(转换)为新序列。
  • SelectMany:用于将多个集合(嵌套集合,如集合的集合)展平为一个集合。

 

 1             var femaleStudents = students.Where(s => s.StudentName == "时光者");
 2             var studentNames = students.Select(s => s.StudentName);
 3 
 4             // 使用SelectMany展平所有学生的课程列表
 5             var allCourses = students.SelectMany(student => student.Courses).ToList();
 6 
 7             // 输出所有课程的名称
 8             foreach (var course in allCourses)
 9             {
10                 Console.WriteLine(course.CourseName);
11             }

 

转换方法

  • ToList:将实现了IEnumerable<T>接口的集合转换为一个List<T>类型的对象,属于将集合转换为特定类型列表的方法。
  • ToArray:将一个实现了IEnumerable<T>接口的集合转换为一个数组,属于将集合转换为数组类型的方法。
  • ToDictionary:将一个IEnumerable<T>集合转换为一个Dictionary<TKey,TValue>键值对集合(字典)的方法,注意 ToDictionary 要求键唯一,否则抛出异常。
  • ToLookup:将一个IEnumerable<T>集合转换为一个泛型Lookup<TKey,TElement>Lookup<TKey,TElement>一个一对多字典,用于将键映射到值的集合。
            var studentList = students.ToList();
            var studentArray = students.ToArray();
            var studentDictionary = students.ToDictionary(s => s.StudentID, s => s.StudentName);
            var studentLookup = students.ToLookup(s => s.ClassID, s => s.StudentName);

元素操作方法

  • First:返回集合中的第一个元素。
  • FirstOrDefault:返回集合中的第一个元素,如果集合中未找到该元素,则返回默认值。
  • Single:返回集合中的单个元素,如果集合中未找到该元素或包含多个元素则抛出异常。
  • SingleOrDefault:返回集合中的单个元素,如果集合中未找到该元素,则返回默认值;如果该集合中包含多个元素,此方法将引发异常。
  • Last:返回集合中的最后一个元素。
  • LastOrDefault:返回集合中的最后一个元素,如果集合中未找到该元素,则返回默认值。
  • ElementAt:返回集合中指定索引处的元素。
  • ElementAtOrDefault:返回集合中指定索引处的元素,如果索引超出范围则返回默认值。
  • DefaultIfEmpty:如果集合为空,则返回一个包含默认值的集合。
1             var firstStudent = students.First();
2             var firstAdult = students.FirstOrDefault(s => s.Birthday <= DateTime.Now.AddYears(-18));
3             var onlyWangWu = students.Single(s => s.StudentName == "王五");
4             var wangWuOrDefault = students.SingleOrDefault(s => s.StudentName == "王六");
5             var lastStudent = students.Last();
6             var lastAdult = students.LastOrDefault(s => s.Birthday <= DateTime.Now.AddYears(-18));
7             var secondStudent = students.ElementAt(1);
8             var tenthStudentOrDefault = students.ElementAtOrDefault(9);
9             var nonEmptyStudents = students.DefaultIfEmpty(new StudentInfo { StudentID = 0, StudentName = "默认Student", Address = "默认" });

排序方法

  • OrderBy:用于对集合进行升序排序。
  • OrderByDescending:用于对集合进行降序排序。
  • ThenBy:按升序对集合中的元素执行后续排序。
  • ThenByDescending:按降序对集合中的元素执行后续排序。
            var sortedByBirthdayAsc = students.OrderBy(s => s.Birthday);
            var sortedByClassIDDesc = students.OrderByDescending(s => s.ClassID);
            var sortedByNameThenClassID = students.OrderBy(s => s.StudentName).ThenBy(s => s.ClassID);
            var sortedThenByDescending = students.OrderBy(s => s.StudentName).ThenBy(s => s.ClassID).ThenByDescending(x => x.Birthday);

聚合方法

  • Count:返回集合中的元素数量。
  • Sum:返回集合中数值类型元素的和。
  • Average:返回集合中数值类型元素的平均值。
  • Min:返回集合中的最小值。
  • Max:返回集合中的最大值。
  • Aggregate:对集合进行自定义聚合操作。
1             int studentCount = students.Count();
2             int totalClassID = students.Sum(s => s.ClassID);
3             double averageAge = students.Average(s => DateTime.Now.Year - s.Birthday.Year);
4             int minClassID = students.Min(s => s.ClassID);
5             int maxClassID = students.Max(s => s.ClassID);
6             string concatenatedNames = students.Aggregate("", (acc, s) => acc == "" ? s.StudentName : acc + ", " + s.StudentName);

集合操作方法

  • Distinct:返回集合中的唯一元素(去除重复项)。
  • Union:返回两个集合的并集(合并后去重)。
  • Intersect:返回两个集合的交集(共有的唯一元素)。
  • Except:返回在第一个集合中存在但不在第二个集合中存在的元素(取集合的差集)。
  • Concat:连接两个集合,返回一个新的序列(保留所有元素,包括重复项)。
            var uniqueClassIDs = students.Select(s => s.ClassID).Distinct();
            var unionClassIDs = uniqueClassIDs.Union(new[] { 103, 104 });
            var intersectClassIDs = uniqueClassIDs.Intersect(new[] { 101, 103 });
            var exceptClassIDs = uniqueClassIDs.Except(new[] { 101 });
            var concatClassIDs = uniqueClassIDs.Concat(new[] { 103, 104 });

分组与连接方法

  • GroupBy:对集合中的元素进行分组。
  • Join:基于匹配键对两个集合的元素进行关联。
  • GroupJoin:基于键值等同性将两个集合的元素进行关联,并对结果进行分组。
 1             var groupedByClassID = students.GroupBy(s => s.ClassID);
 2 
 3             foreach (var group in groupedByClassID)
 4             {
 5                 Console.WriteLine($"班级ID: {group.Key}");
 6                 foreach (var student in group)
 7                 {
 8                     Console.WriteLine($"  学生姓名: {student.StudentName}");
 9                 }
10             }
11 
12             // 连接两个集合(内连接查询)
13             var otherStudent = new List<StudentInfo>
14             {
15                new StudentInfo
16                {
17                    StudentID=4,
18                    StudentName="摇一摇",
19                    Birthday=Convert.ToDateTime("1997-10-25"),
20                    ClassID=101,
21                    Courses = new List<Course>
22                    {
23                        new Course { CourseID = 101, CourseName = "语文" },
24                        new Course { CourseID = 102, CourseName = "数学" }
25                    }
26                }
27             };
28 
29             var listJoin = students.Join(
30                 otherStudent, // 要连接的第二个集合
31                 s1 => s1.StudentID, // 从第一个集合中提取键
32                 s2 => s2.StudentID, // 从第二个集合中提取键
33                 (s1, s2) => new // 结果选择器,指定如何从两个匹配元素创建结果
34                 {
35                     StudentID = s1.StudentID,
36                     StudentName = s1.StudentName,
37                     Birthday = s1.Birthday,
38                     ClassID = s1.ClassID,
39                     Address = s1.Address,
40                     Courses = s1.Courses,
41                     OtherStudentName = s2.StudentName
42                 });
43 
44             //使用 GroupJoin 方法实现两个集合的左连接(Left Join)
45             //目标:获取所有课程及选修学生(即使无人选修也要显示课程)
46             var courseStudentGroups = courses.GroupJoin(
47                 students.SelectMany(
48                     student => student.Courses,
49                     (student, course) => new { Student = student, Course = course }
50                 ),
51                 course => course.CourseID,
52                 studentCoursePair => studentCoursePair.Course.CourseID,
53                 // 结果投影:生成课程名称及对应的学生列表
54                 (course, matchedStudents) => new
55                 {
56                     CourseName = course.CourseName,
57                     Students = matchedStudents
58                         .Select(pair => pair.Student.StudentName)
59                         .DefaultIfEmpty("(无学生)")
60                         .ToList()
61                 }
62             ).ToList();
63 
64             // 输出结果
65             foreach (var group in courseStudentGroups)
66             {
67                 Console.WriteLine("-------------------");
68                 Console.WriteLine($"课程:{group.CourseName}");
69                 Console.WriteLine($"选修学生:{string.Join(", ", group.Students)}");
70                 Console.WriteLine("-------------------");
71             }
View Code

跳过与获取指定数量的元素(常用作分页)

  • Skip:用于跳过集合中指定数量的元素,并返回剩余的元素序列。
  • Take:用于从集合的开头获取指定数量的元素,并返回一个新的序列。
 1             var skippedStudents = students.Skip(1);
 2             var takenStudents = students.Take(2);
 3 
 4             //数据分页查询(Skip + Take)
 5             int pageNumber = 2;
 6             int pageSize = 10;
 7             var pagedUsers = skippedStudents
 8                 .OrderBy(u => u.ClassID) // 必须排序
 9                 .Skip((pageNumber - 1) * pageSize)
10                 .Take(pageSize)
11                 .ToList();

 

条件判断方法

  • All:判断集合中的所有元素是否都满足条件。
  • Any:判断集合中是否包含元素或存在元素满足指定条件。
  • Contains:用于判断集合中是否包含指定的元素。
1             bool allAdults = students.All(s => s.Birthday <= DateTime.Now.AddYears(-18));
2             bool anyAdults = students.Any(s => s.Birthday <= DateTime.Now.AddYears(-18));
3             bool containsWangWu = students.Contains(students.First(s => s.StudentName == "王五"));

更多方法查询

image

查询语法

LINQ提供了类似于SQL的查询语法,允许开发者以几乎相同的方式对不同类型的数据源进行查询。查询语法使用from、where、select、orderby等关键字。

 1             var querySyntaxResult = from student in students
 2                                     where student.ClassID == 101
 3                                     orderby student.StudentName ascending
 4                                     select student;
 5 
 6             Console.WriteLine("查询语法结果:");
 7             foreach (var student in querySyntaxResult)
 8             {
 9                 Console.WriteLine($"{student.StudentName}, ClassID: {student.ClassID}");
10             }

查询关键字:

  • from: 指定数据源和范围变量(类似于迭代变量)。
  • where: 基于由逻辑 AND 和 OR 运算符(&& 或 ||)分隔的一个或多个布尔表达式筛选源元素。
  • select: 指定执行查询时,所返回序列中元素的类型和形状。
  • group: 根据指定的密钥值对查询结果分组。
  • into: 提供可作为对 join、group 或 select 子句结果引用的标识符(简单理解用于将配对的结果收集到一个临时序列)。
  • orderby: 根据元素类型的默认比较器对查询结果进行升序或降序排序。
  • join: 基于两个指定匹配条件间的相等比较而联接两个数据源(简单理解根据指定的键将两个序列中的元素配对)。
  • let: 引入范围变量,在查询表达式中存储子表达式结果。
  • in: join子句中的上下文关键字。
  • on: join子句中的上下文关键字。
  • equals: join子句中的上下文关键字。
  • by: group 子句中的上下文关键字。
  • ascending: orderby子句中的上下文关键字。
  • descending: orderby子句中的上下文关键字。

方法语法

方法语法也称为扩展方法语法,使用点号“.”和一系列扩展方法来构建查询。

 1             var methodSyntaxResult = students
 2                                     .Where(student => student.ClassID == 101)
 3                                     .OrderBy(student => student.StudentName)
 4                                     .ToList();
 5 
 6 
 7             Console.WriteLine("方法语法结果:");
 8             foreach (var student in methodSyntaxResult)
 9             {
10                 Console.WriteLine($"{student.StudentName}, ClassID: {student.ClassID}");
11             }

混合查询和方法语法

            var mixedResult = (from student in students
                               where student.ClassID == 101
                               where student.Courses.Any(course => course.CourseName == "数学")
                               orderby student.StudentName ascending
                               select student)
                       .Take(2)
                       .ToList();

            // 输出结果
            Console.WriteLine("混合查询结果:");
            foreach (var student in mixedResult)
            {
                Console.WriteLine($"{student.StudentName}, ClassID: {student.ClassID}");
            }

参考文章

转载:https://cloud.tencent.com/developer/article/2513974

 

posted @ 2025-11-28 14:24  家煜宝宝  阅读(13)  评论(0)    收藏  举报