本章概述

LINQ(Language Integrated Query,语言集成查询)是C#中最强大和优雅的特性之一,它将查询功能直接集成到C#语言中。LINQ提供了一致的查询体验,无论数据源是对象集合、数据库、XML还是其他数据源。表达式树则是LINQ的核心基础,它将代码表示为数据结构,使得查询可以被分析、修改和转换。

学习目标

通过本章学习,你将能够: - 理解LINQ的核心概念和查询语法 - 掌握LINQ to Objects的各种操作 - 学会使用方法语法和查询语法 - 理解延迟执行和立即执行的区别 - 掌握表达式树的构建和使用 - 学习自定义LINQ扩展方法 - 了解LINQ的性能优化技巧

1. LINQ基础

1.1 LINQ概念和语法

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

public class LinqBasics
{
    public static void DemonstrateLinqBasics()
    {
        Console.WriteLine("\n=== LINQ基础演示 ===");
        
        // 示例数据
        var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        var names = new[] { "Alice", "Bob", "Charlie", "David", "Eve" };
        
        Console.WriteLine("\n--- 查询语法 vs 方法语法 ---");
        DemonstrateQuerySyntax(numbers);
        DemonstrateMethodSyntax(numbers);
        
        Console.WriteLine("\n--- 基本查询操作 ---");
        DemonstrateBasicOperations(numbers, names);
    }
    
    private static void DemonstrateQuerySyntax(int[] numbers)
    {
        Console.WriteLine("查询语法示例:");
        
        // 查询语法 - 类似SQL的语法
        var evenNumbers = from n in numbers
                         where n % 2 == 0
                         select n;
        
        var squaredNumbers = from n in numbers
                           where n > 5
                           select n * n;
        
        var numbersWithIndex = from n in numbers.Select((value, index) => new { Value = value, Index = index })
                              where n.Index % 2 == 0
                              select $"索引{n.Index}: {n.Value}";
        
        Console.WriteLine($"偶数: [{string.Join(", ", evenNumbers)}]");
        Console.WriteLine($"大于5的数的平方: [{string.Join(", ", squaredNumbers)}]");
        Console.WriteLine($"偶数索引的元素: [{string.Join(", ", numbersWithIndex)}]");
    }
    
    private static void DemonstrateMethodSyntax(int[] numbers)
    {
        Console.WriteLine("\n方法语法示例:");
        
        // 方法语法 - 使用扩展方法链式调用
        var evenNumbers = numbers.Where(n => n % 2 == 0);
        
        var squaredNumbers = numbers
            .Where(n => n > 5)
            .Select(n => n * n);
        
        var numbersWithIndex = numbers
            .Select((value, index) => new { Value = value, Index = index })
            .Where(item => item.Index % 2 == 0)
            .Select(item => $"索引{item.Index}: {item.Value}");
        
        Console.WriteLine($"偶数: [{string.Join(", ", evenNumbers)}]");
        Console.WriteLine($"大于5的数的平方: [{string.Join(", ", squaredNumbers)}]");
        Console.WriteLine($"偶数索引的元素: [{string.Join(", ", numbersWithIndex)}]");
    }
    
    private static void DemonstrateBasicOperations(int[] numbers, string[] names)
    {
        Console.WriteLine("\n基本查询操作:");
        
        // 过滤 (Where)
        var evenNumbers = numbers.Where(n => n % 2 == 0);
        Console.WriteLine($"偶数: [{string.Join(", ", evenNumbers)}]");
        
        // 投影 (Select)
        var lengths = names.Select(name => name.Length);
        Console.WriteLine($"名字长度: [{string.Join(", ", lengths)}]");
        
        // 排序 (OrderBy, OrderByDescending)
        var sortedNames = names.OrderBy(name => name.Length).ThenBy(name => name);
        Console.WriteLine($"按长度排序的名字: [{string.Join(", ", sortedNames)}]");
        
        // 分组 (GroupBy)
        var groupedByLength = names.GroupBy(name => name.Length);
        Console.WriteLine("按长度分组:");
        foreach (var group in groupedByLength)
        {
            Console.WriteLine($"  长度{group.Key}: [{string.Join(", ", group)}]");
        }
        
        // 聚合操作
        Console.WriteLine($"\n聚合操作:");
        Console.WriteLine($"总数: {numbers.Count()}");
        Console.WriteLine($"总和: {numbers.Sum()}");
        Console.WriteLine($"平均值: {numbers.Average():F2}");
        Console.WriteLine($"最大值: {numbers.Max()}");
        Console.WriteLine($"最小值: {numbers.Min()}");
    }
}

1.2 延迟执行和立即执行

public class LinqExecution
{
    public static void DemonstrateExecution()
    {
        Console.WriteLine("\n=== LINQ执行模式演示 ===");
        
        Console.WriteLine("\n--- 延迟执行 ---");
        DemonstrateDeferredExecution();
        
        Console.WriteLine("\n--- 立即执行 ---");
        DemonstrateImmediateExecution();
        
        Console.WriteLine("\n--- 执行时机对比 ---");
        CompareExecutionTiming();
    }
    
    private static void DemonstrateDeferredExecution()
    {
        var numbers = new List<int> { 1, 2, 3, 4, 5 };
        
        // 延迟执行 - 查询定义时不执行
        var evenNumbers = numbers.Where(n => 
        {
            Console.WriteLine($"  检查数字: {n}");
            return n % 2 == 0;
        });
        
        Console.WriteLine("查询已定义,但尚未执行");
        
        // 修改原始数据
        numbers.Add(6);
        numbers.Add(7);
        
        Console.WriteLine("\n第一次枚举:");
        foreach (var num in evenNumbers)
        {
            Console.WriteLine($"结果: {num}");
        }
        
        Console.WriteLine("\n第二次枚举:");
        foreach (var num in evenNumbers)
        {
            Console.WriteLine($"结果: {num}");
        }
    }
    
    private static void DemonstrateImmediateExecution()
    {
        var numbers = new List<int> { 1, 2, 3, 4, 5 };
        
        // 立即执行 - 使用ToList()强制执行
        var evenNumbers = numbers.Where(n => 
        {
            Console.WriteLine($"  检查数字: {n}");
            return n % 2 == 0;
        }).ToList(); // 立即执行
        
        Console.WriteLine("查询已执行并缓存结果");
        
        // 修改原始数据
        numbers.Add(6);
        numbers.Add(7);
        
        Console.WriteLine("\n枚举缓存的结果:");
        foreach (var num in evenNumbers)
        {
            Console.WriteLine($"结果: {num}");
        }
    }
    
    private static void CompareExecutionTiming()
    {
        var numbers = Enumerable.Range(1, 1000000);
        
        var sw = System.Diagnostics.Stopwatch.StartNew();
        
        // 延迟执行 - 只是定义查询
        var deferredQuery = numbers
            .Where(n => n % 2 == 0)
            .Select(n => n * n)
            .Where(n => n > 1000);
        
        sw.Stop();
        Console.WriteLine($"定义延迟查询耗时: {sw.ElapsedMilliseconds}ms");
        
        sw.Restart();
        
        // 执行延迟查询
        var deferredResult = deferredQuery.Take(10).ToList();
        
        sw.Stop();
        Console.WriteLine($"执行延迟查询(取前10个)耗时: {sw.ElapsedMilliseconds}ms");
        
        sw.Restart();
        
        // 立即执行
        var immediateResult = numbers
            .Where(n => n % 2 == 0)
            .Select(n => n * n)
            .Where(n => n > 1000)
            .Take(10)
            .ToList();
        
        sw.Stop();
        Console.WriteLine($"立即执行查询(取前10个)耗时: {sw.ElapsedMilliseconds}ms");
        
        Console.WriteLine($"延迟查询结果: [{string.Join(", ", deferredResult)}]");
        Console.WriteLine($"立即执行结果: [{string.Join(", ", immediateResult)}]");
    }
}

2. LINQ to Objects详解

2.1 过滤和投影操作

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Major { get; set; }
    public double GPA { get; set; }
    public List<string> Courses { get; set; } = new List<string>();
    
    public override string ToString()
    {
        return $"Student(Id={Id}, Name={Name}, Age={Age}, Major={Major}, GPA={GPA:F2})";
    }
}

public class LinqFiltering
{
    public static void DemonstrateFiltering()
    {
        Console.WriteLine("\n=== LINQ过滤和投影演示 ===");
        
        var students = GetSampleStudents();
        
        Console.WriteLine("\n--- Where过滤 ---");
        DemonstrateWhere(students);
        
        Console.WriteLine("\n--- Select投影 ---");
        DemonstrateSelect(students);
        
        Console.WriteLine("\n--- SelectMany扁平化 ---");
        DemonstrateSelectMany(students);
        
        Console.WriteLine("\n--- 复杂查询组合 ---");
        DemonstrateComplexQueries(students);
    }
    
    private static List<Student> GetSampleStudents()
    {
        return new List<Student>
        {
            new Student { Id = 1, Name = "张三", Age = 20, Major = "计算机科学", GPA = 3.8, 
                         Courses = new List<string> { "数据结构", "算法", "数据库" } },
            new Student { Id = 2, Name = "李四", Age = 22, Major = "软件工程", GPA = 3.6, 
                         Courses = new List<string> { "软件设计", "项目管理", "测试" } },
            new Student { Id = 3, Name = "王五", Age = 19, Major = "计算机科学", GPA = 3.9, 
                         Courses = new List<string> { "机器学习", "人工智能", "数据挖掘" } },
            new Student { Id = 4, Name = "赵六", Age = 21, Major = "信息系统", GPA = 3.4, 
                         Courses = new List<string> { "系统分析", "数据库", "网络" } },
            new Student { Id = 5, Name = "钱七", Age = 23, Major = "软件工程", GPA = 3.7, 
                         Courses = new List<string> { "架构设计", "微服务", "云计算" } }
        };
    }
    
    private static void DemonstrateWhere(List<Student> students)
    {
        // 简单条件过滤
        var youngStudents = students.Where(s => s.Age < 21);
        Console.WriteLine("年龄小于21的学生:");
        foreach (var student in youngStudents)
        {
            Console.WriteLine($"  {student}");
        }
        
        // 复合条件过滤
        var excellentCSStudents = students.Where(s => s.Major == "计算机科学" && s.GPA > 3.7);
        Console.WriteLine("\n优秀的计算机科学学生:");
        foreach (var student in excellentCSStudents)
        {
            Console.WriteLine($"  {student}");
        }
        
        // 使用索引的过滤
        var evenIndexStudents = students.Where((student, index) => index % 2 == 0);
        Console.WriteLine("\n偶数索引位置的学生:");
        foreach (var student in evenIndexStudents)
        {
            Console.WriteLine($"  {student}");
        }
    }
    
    private static void DemonstrateSelect(List<Student> students)
    {
        // 简单投影
        var names = students.Select(s => s.Name);
        Console.WriteLine($"学生姓名: [{string.Join(", ", names)}]");
        
        // 计算投影
        var ageInMonths = students.Select(s => new { Name = s.Name, AgeInMonths = s.Age * 12 });
        Console.WriteLine("\n学生年龄(月):");
        foreach (var item in ageInMonths)
        {
            Console.WriteLine($"  {item.Name}: {item.AgeInMonths}个月");
        }
        
        // 复杂对象投影
        var studentSummary = students.Select(s => new
        {
            s.Name,
            s.Major,
            Grade = s.GPA >= 3.7 ? "优秀" : s.GPA >= 3.5 ? "良好" : "一般",
            CourseCount = s.Courses.Count
        });
        
        Console.WriteLine("\n学生摘要:");
        foreach (var summary in studentSummary)
        {
            Console.WriteLine($"  {summary.Name} ({summary.Major}) - {summary.Grade}, {summary.CourseCount}门课程");
        }
        
        // 带索引的投影
        var indexedStudents = students.Select((student, index) => new
        {
            Index = index + 1,
            student.Name,
            student.GPA
        });
        
        Console.WriteLine("\n带序号的学生列表:");
        foreach (var item in indexedStudents)
        {
            Console.WriteLine($"  {item.Index}. {item.Name} (GPA: {item.GPA:F2})");
        }
    }
    
    private static void DemonstrateSelectMany(List<Student> students)
    {
        // 扁平化课程列表
        var allCourses = students.SelectMany(s => s.Courses);
        Console.WriteLine($"所有课程: [{string.Join(", ", allCourses)}]");
        
        // 带学生信息的课程列表
        var coursesWithStudent = students.SelectMany(s => s.Courses, 
            (student, course) => new { Student = student.Name, Course = course });
        
        Console.WriteLine("\n学生-课程对应关系:");
        foreach (var item in coursesWithStudent)
        {
            Console.WriteLine($"  {item.Student} -> {item.Course}");
        }
        
        // 去重的课程列表
        var uniqueCourses = students.SelectMany(s => s.Courses).Distinct();
        Console.WriteLine($"\n去重后的课程: [{string.Join(", ", uniqueCourses)}]");
        
        // 复杂的SelectMany示例
        var majorCourseGroups = students
            .GroupBy(s => s.Major)
            .SelectMany(g => g.SelectMany(s => s.Courses).Distinct(), 
                       (group, course) => new { Major = group.Key, Course = course });
        
        Console.WriteLine("\n专业-课程分组:");
        foreach (var group in majorCourseGroups.GroupBy(x => x.Major))
        {
            Console.WriteLine($"  {group.Key}: [{string.Join(", ", group.Select(x => x.Course))}]");
        }
    }
    
    private static void DemonstrateComplexQueries(List<Student> students)
    {
        // 复杂查询:找出每个专业GPA最高的学生
        var topStudentsByMajor = students
            .GroupBy(s => s.Major)
            .Select(g => g.OrderByDescending(s => s.GPA).First());
        
        Console.WriteLine("每个专业GPA最高的学生:");
        foreach (var student in topStudentsByMajor)
        {
            Console.WriteLine($"  {student}");
        }
        
        // 复杂查询:找出选修了特定课程的学生
        var studentsWithDatabase = students
            .Where(s => s.Courses.Contains("数据库"))
            .Select(s => new { s.Name, s.Major, s.GPA });
        
        Console.WriteLine("\n选修数据库课程的学生:");
        foreach (var student in studentsWithDatabase)
        {
            Console.WriteLine($"  {student.Name} ({student.Major}) - GPA: {student.GPA:F2}");
        }
        
        // 复杂查询:统计每门课程的选修人数
        var courseStatistics = students
            .SelectMany(s => s.Courses)
            .GroupBy(course => course)
            .Select(g => new { Course = g.Key, Count = g.Count() })
            .OrderByDescending(x => x.Count);
        
        Console.WriteLine("\n课程选修统计:");
        foreach (var stat in courseStatistics)
        {
            Console.WriteLine($"  {stat.Course}: {stat.Count}人选修");
        }
    }
}

2.3 集合操作和连接

public class Course
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Department { get; set; }
    public int Credits { get; set; }
    
    public override string ToString()
    {
        return $"Course(Id={Id}, Name={Name}, Department={Department}, Credits={Credits})";
    }
}

public class Enrollment
{
    public int StudentId { get; set; }
    public int CourseId { get; set; }
    public string Grade { get; set; }
    public DateTime EnrollmentDate { get; set; }
}

public class LinqSetOperations
{
    public static void DemonstrateSetOperations()
    {
        Console.WriteLine("\n=== LINQ集合操作和连接演示 ===");
        
        var students = GetStudents();
        var courses = GetCourses();
        var enrollments = GetEnrollments();
        
        Console.WriteLine("\n--- 集合操作 ---");
        DemonstrateSetOps(students);
        
        Console.WriteLine("\n--- 连接操作 ---");
        DemonstrateJoins(students, courses, enrollments);
        
        Console.WriteLine("\n--- 复杂连接查询 ---");
        DemonstrateComplexJoins(students, courses, enrollments);
    }
    
    private static List<Student> GetStudents()
    {
        return new List<Student>
        {
            new Student { Id = 1, Name = "张三", Major = "计算机科学" },
            new Student { Id = 2, Name = "李四", Major = "软件工程" },
            new Student { Id = 3, Name = "王五", Major = "计算机科学" },
            new Student { Id = 4, Name = "赵六", Major = "信息系统" }
        };
    }
    
    private static List<Course> GetCourses()
    {
        return new List<Course>
        {
            new Course { Id = 101, Name = "数据结构", Department = "计算机", Credits = 3 },
            new Course { Id = 102, Name = "算法分析", Department = "计算机", Credits = 3 },
            new Course { Id = 103, Name = "数据库系统", Department = "计算机", Credits = 4 },
            new Course { Id = 201, Name = "软件工程", Department = "软件", Credits = 3 },
            new Course { Id = 202, Name = "项目管理", Department = "软件", Credits = 2 }
        };
    }
    
    private static List<Enrollment> GetEnrollments()
    {
        return new List<Enrollment>
        {
            new Enrollment { StudentId = 1, CourseId = 101, Grade = "A", EnrollmentDate = DateTime.Now.AddDays(-30) },
            new Enrollment { StudentId = 1, CourseId = 102, Grade = "B+", EnrollmentDate = DateTime.Now.AddDays(-25) },
            new Enrollment { StudentId = 2, CourseId = 101, Grade = "B", EnrollmentDate = DateTime.Now.AddDays(-28) },
            new Enrollment { StudentId = 2, CourseId = 201, Grade = "A-", EnrollmentDate = DateTime.Now.AddDays(-20) },
            new Enrollment { StudentId = 3, CourseId = 102, Grade = "A", EnrollmentDate = DateTime.Now.AddDays(-22) },
            new Enrollment { StudentId = 3, CourseId = 103, Grade = "B+", EnrollmentDate = DateTime.Now.AddDays(-15) }
        };
    }
    
    private static void DemonstrateSetOps(List<Student> students)
    {
        var csStudents = students.Where(s => s.Major == "计算机科学").Select(s => s.Name);
        var seStudents = students.Where(s => s.Major == "软件工程").Select(s => s.Name);
        var allMajors = students.Select(s => s.Major);
        
        Console.WriteLine($"计算机科学学生: [{string.Join(", ", csStudents)}]");
        Console.WriteLine($"软件工程学生: [{string.Join(", ", seStudents)}]");
        
        // Union - 并集
        var unionResult = csStudents.Union(seStudents);
        Console.WriteLine($"\nUnion(并集): [{string.Join(", ", unionResult)}]");
        
        // Intersect - 交集
        var intersectResult = csStudents.Intersect(seStudents);
        Console.WriteLine($"Intersect(交集): [{string.Join(", ", intersectResult)}]");
        
        // Except - 差集
        var exceptResult = csStudents.Except(seStudents);
        Console.WriteLine($"Except(差集): [{string.Join(", ", exceptResult)}]");
        
        // Distinct - 去重
        var distinctMajors = allMajors.Distinct();
        Console.WriteLine($"\nDistinct专业: [{string.Join(", ", distinctMajors)}]");
        
        // Concat - 连接(不去重)
        var concatResult = csStudents.Concat(seStudents);
        Console.WriteLine($"Concat(连接): [{string.Join(", ", concatResult)}]");
        
        // 自定义比较器的集合操作
        var names1 = new[] { "张三", "李四" };
        var names2 = new[] { "ZHANGSAN", "王五" };
        
        var customUnion = names1.Union(names2, StringComparer.OrdinalIgnoreCase);
        Console.WriteLine($"\n自定义比较器Union: [{string.Join(", ", customUnion)}]");
    }
    
    private static void DemonstrateJoins(List<Student> students, List<Course> courses, List<Enrollment> enrollments)
    {
        // Inner Join - 内连接
        var innerJoin = from s in students
                       join e in enrollments on s.Id equals e.StudentId
                       join c in courses on e.CourseId equals c.Id
                       select new
                       {
                           StudentName = s.Name,
                           CourseName = c.Name,
                           Grade = e.Grade,
                           Credits = c.Credits
                       };
        
        Console.WriteLine("Inner Join - 学生选课信息:");
        foreach (var item in innerJoin)
        {
            Console.WriteLine($"  {item.StudentName} - {item.CourseName} ({item.Credits}学分) - 成绩: {item.Grade}");
        }
        
        // Left Join - 左连接(使用GroupJoin)
        var leftJoin = from s in students
                      join e in enrollments on s.Id equals e.StudentId into studentEnrollments
                      from se in studentEnrollments.DefaultIfEmpty()
                      join c in courses on se?.CourseId equals c.Id into enrollmentCourses
                      from ec in enrollmentCourses.DefaultIfEmpty()
                      select new
                      {
                          StudentName = s.Name,
                          CourseName = ec?.Name ?? "未选课",
                          Grade = se?.Grade ?? "N/A"
                      };
        
        Console.WriteLine("\nLeft Join - 所有学生(包括未选课):");
        foreach (var item in leftJoin)
        {
            Console.WriteLine($"  {item.StudentName} - {item.CourseName} - 成绩: {item.Grade}");
        }
        
        // Group Join - 分组连接
        var groupJoin = from s in students
                       join e in enrollments on s.Id equals e.StudentId into studentEnrollments
                       select new
                       {
                           Student = s.Name,
                           EnrollmentCount = studentEnrollments.Count(),
                           Courses = studentEnrollments.Join(courses, 
                               enrollment => enrollment.CourseId,
                               course => course.Id,
                               (enrollment, course) => new { course.Name, enrollment.Grade })
                       };
        
        Console.WriteLine("\nGroup Join - 学生选课统计:");
        foreach (var item in groupJoin)
        {
            Console.WriteLine($"  {item.Student} - 选课数: {item.EnrollmentCount}");
            foreach (var course in item.Courses)
            {
                Console.WriteLine($"    {course.Name} - {course.Grade}");
            }
        }
    }
    
    private static void DemonstrateComplexJoins(List<Student> students, List<Course> courses, List<Enrollment> enrollments)
    {
        // 复杂查询:每个学生的总学分和平均成绩
        var studentStats = from s in students
                          join e in enrollments on s.Id equals e.StudentId into studentEnrollments
                          from se in studentEnrollments.DefaultIfEmpty()
                          join c in courses on se?.CourseId equals c.Id into enrollmentCourses
                          from ec in enrollmentCourses.DefaultIfEmpty()
                          group new { Student = s, Course = ec, Enrollment = se } by s into studentGroup
                          select new
                          {
                              StudentName = studentGroup.Key.Name,
                              Major = studentGroup.Key.Major,
                              TotalCredits = studentGroup.Where(x => x.Course != null).Sum(x => x.Course.Credits),
                              CourseCount = studentGroup.Count(x => x.Course != null),
                              Grades = studentGroup.Where(x => x.Enrollment != null)
                                  .Select(x => x.Enrollment.Grade).ToList()
                          };
        
        Console.WriteLine("学生统计信息:");
        foreach (var stat in studentStats)
        {
            Console.WriteLine($"  {stat.StudentName} ({stat.Major}):");
            Console.WriteLine($"    总学分: {stat.TotalCredits}");
            Console.WriteLine($"    选课数: {stat.CourseCount}");
            Console.WriteLine($"    成绩: [{string.Join(", ", stat.Grades)}]");
        }
        
        // 复杂查询:每门课程的选课统计
        var courseStats = from c in courses
                         join e in enrollments on c.Id equals e.CourseId into courseEnrollments
                         from ce in courseEnrollments.DefaultIfEmpty()
                         join s in students on ce?.StudentId equals s.Id into enrollmentStudents
                         from es in enrollmentStudents.DefaultIfEmpty()
                         group new { Course = c, Enrollment = ce, Student = es } by c into courseGroup
                         select new
                         {
                             CourseName = courseGroup.Key.Name,
                             Department = courseGroup.Key.Department,
                             Credits = courseGroup.Key.Credits,
                             EnrollmentCount = courseGroup.Count(x => x.Student != null),
                             Students = courseGroup.Where(x => x.Student != null)
                                 .Select(x => new { x.Student.Name, x.Enrollment.Grade }).ToList()
                         };
        
        Console.WriteLine("\n课程统计信息:");
        foreach (var stat in courseStats)
        {
            Console.WriteLine($"  {stat.CourseName} ({stat.Department}系, {stat.Credits}学分):");
            Console.WriteLine($"    选课人数: {stat.EnrollmentCount}");
            if (stat.Students.Any())
            {
                Console.WriteLine($"    学生成绩:");
                foreach (var student in stat.Students)
                {
                    Console.WriteLine($"      {student.Name}: {student.Grade}");
                }
            }
        }
    }
}

3. 表达式树基础

3.1 表达式树概念和构建

using System.Linq.Expressions;

public class ExpressionTreeBasics
{
    public static void DemonstrateExpressionTrees()
    {
        Console.WriteLine("\n=== 表达式树基础演示 ===");
        
        Console.WriteLine("\n--- 基本表达式树 ---");
        DemonstrateBasicExpressions();
        
        Console.WriteLine("\n--- 复杂表达式树 ---");
        DemonstrateComplexExpressions();
        
        Console.WriteLine("\n--- 表达式树分析 ---");
        DemonstrateExpressionAnalysis();
        
        Console.WriteLine("\n--- 动态表达式构建 ---");
        DemonstrateDynamicExpressions();
    }
    
    private static void DemonstrateBasicExpressions()
    {
        // 常量表达式
        Expression<Func<int>> constantExpr = () => 42;
        Console.WriteLine($"常量表达式: {constantExpr}");
        Console.WriteLine($"执行结果: {constantExpr.Compile()()}");
        
        // 参数表达式
        Expression<Func<int, int>> parameterExpr = x => x * 2;
        Console.WriteLine($"\n参数表达式: {parameterExpr}");
        Console.WriteLine($"执行结果 f(5): {parameterExpr.Compile()(5)}");
        
        // 二元运算表达式
        Expression<Func<int, int, int>> binaryExpr = (x, y) => x + y;
        Console.WriteLine($"\n二元运算表达式: {binaryExpr}");
        Console.WriteLine($"执行结果 f(3, 4): {binaryExpr.Compile()(3, 4)}");
        
        // 条件表达式
        Expression<Func<int, string>> conditionalExpr = x => x > 0 ? "正数" : "非正数";
        Console.WriteLine($"\n条件表达式: {conditionalExpr}");
        Console.WriteLine($"执行结果 f(5): {conditionalExpr.Compile()(5)}");
        Console.WriteLine($"执行结果 f(-3): {conditionalExpr.Compile()(-3)}");
        
        // 方法调用表达式
        Expression<Func<string, int>> methodCallExpr = s => s.Length;
        Console.WriteLine($"\n方法调用表达式: {methodCallExpr}");
        Console.WriteLine($"执行结果 f(\"Hello\"): {methodCallExpr.Compile()("Hello")}");
    }
    
    private static void DemonstrateComplexExpressions()
    {
        // 复杂的数学表达式
        Expression<Func<double, double, double>> mathExpr = (x, y) => Math.Sqrt(x * x + y * y);
        Console.WriteLine($"数学表达式: {mathExpr}");
        Console.WriteLine($"执行结果 f(3, 4): {mathExpr.Compile()(3, 4):F2}");
        
        // 字符串操作表达式
        Expression<Func<string, string, bool>> stringExpr = (s1, s2) => s1.Contains(s2) && s1.Length > 5;
        Console.WriteLine($"\n字符串表达式: {stringExpr}");
        Console.WriteLine($"执行结果 f(\"Hello World\", \"World\"): {stringExpr.Compile()("Hello World", "World")}");
        
        // 对象属性访问表达式
        Expression<Func<Student, bool>> propertyExpr = s => s.Age > 20 && s.Major == "计算机科学";
        Console.WriteLine($"\n属性访问表达式: {propertyExpr}");
        
        var student = new Student { Name = "张三", Age = 21, Major = "计算机科学" };
        Console.WriteLine($"执行结果: {propertyExpr.Compile()(student)}");
        
        // 集合操作表达式
        Expression<Func<List<int>, int>> collectionExpr = list => list.Where(x => x % 2 == 0).Sum();
        Console.WriteLine($"\n集合操作表达式: {collectionExpr}");
        
        var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
        Console.WriteLine($"执行结果: {collectionExpr.Compile()(numbers)}");
    }
    
    private static void DemonstrateExpressionAnalysis()
    {
        Expression<Func<int, int, int>> expr = (x, y) => x * x + y * y;
        
        Console.WriteLine($"表达式: {expr}");
        Console.WriteLine($"表达式类型: {expr.GetType()}");
        Console.WriteLine($"Body类型: {expr.Body.GetType()}");
        Console.WriteLine($"参数数量: {expr.Parameters.Count}");
        
        // 分析表达式结构
        AnalyzeExpression(expr.Body, 0);
    }
    
    private static void AnalyzeExpression(Expression expr, int depth)
    {
        string indent = new string(' ', depth * 2);
        Console.WriteLine($"{indent}节点类型: {expr.NodeType}, 表达式类型: {expr.Type}");
        
        switch (expr)
        {
            case BinaryExpression binary:
                Console.WriteLine($"{indent}二元运算: {binary.NodeType}");
                Console.WriteLine($"{indent}左操作数:");
                AnalyzeExpression(binary.Left, depth + 1);
                Console.WriteLine($"{indent}右操作数:");
                AnalyzeExpression(binary.Right, depth + 1);
                break;
                
            case ParameterExpression parameter:
                Console.WriteLine($"{indent}参数: {parameter.Name}");
                break;
                
            case ConstantExpression constant:
                Console.WriteLine($"{indent}常量: {constant.Value}");
                break;
                
            case MethodCallExpression methodCall:
                Console.WriteLine($"{indent}方法调用: {methodCall.Method.Name}");
                if (methodCall.Object != null)
                {
                    Console.WriteLine($"{indent}调用对象:");
                    AnalyzeExpression(methodCall.Object, depth + 1);
                }
                foreach (var arg in methodCall.Arguments)
                {
                    Console.WriteLine($"{indent}参数:");
                    AnalyzeExpression(arg, depth + 1);
                }
                break;
        }
    }
    
    private static void DemonstrateDynamicExpressions()
    {
        // 动态构建表达式:x => x * factor
        var parameter = Expression.Parameter(typeof(int), "x");
        var factor = Expression.Constant(3);
        var multiply = Expression.Multiply(parameter, factor);
        var lambda = Expression.Lambda<Func<int, int>>(multiply, parameter);
        
        Console.WriteLine($"动态构建的表达式: {lambda}");
        Console.WriteLine($"执行结果 f(5): {lambda.Compile()(5)}");
        
        // 动态构建条件表达式:x => x > threshold ? x : 0
        var threshold = Expression.Constant(10);
        var condition = Expression.GreaterThan(parameter, threshold);
        var zero = Expression.Constant(0);
        var conditional = Expression.Condition(condition, parameter, zero);
        var conditionalLambda = Expression.Lambda<Func<int, int>>(conditional, parameter);
        
        Console.WriteLine($"\n动态条件表达式: {conditionalLambda}");
        Console.WriteLine($"执行结果 f(15): {conditionalLambda.Compile()(15)}");
        Console.WriteLine($"执行结果 f(5): {conditionalLambda.Compile()(5)}");
        
        // 动态构建属性访问表达式
        var studentParam = Expression.Parameter(typeof(Student), "s");
        var nameProperty = Expression.Property(studentParam, "Name");
        var nameLength = Expression.Property(nameProperty, "Length");
        var nameLengthLambda = Expression.Lambda<Func<Student, int>>(nameLength, studentParam);
        
        Console.WriteLine($"\n动态属性访问表达式: {nameLengthLambda}");
        var testStudent = new Student { Name = "张三" };
        Console.WriteLine($"执行结果: {nameLengthLambda.Compile()(testStudent)}");
    }
}

3.2 表达式树的修改和转换

public class ExpressionTreeModification
{
    public static void DemonstrateExpressionModification()
    {
        Console.WriteLine("\n=== 表达式树修改和转换演示 ===");
        
        Console.WriteLine("\n--- 表达式树访问者模式 ---");
        DemonstrateExpressionVisitor();
        
        Console.WriteLine("\n--- 参数替换 ---");
        DemonstrateParameterReplacement();
        
        Console.WriteLine("\n--- 表达式组合 ---");
        DemonstrateExpressionComposition();
    }
    
    private static void DemonstrateExpressionVisitor()
    {
        // 创建一个表达式树访问者来计算常量
        var expr = Expression.Lambda<Func<int, int>>(
            Expression.Add(
                Expression.Multiply(Expression.Parameter(typeof(int), "x"), Expression.Constant(2)),
                Expression.Constant(10)
            ),
            Expression.Parameter(typeof(int), "x")
        );
        
        Console.WriteLine($"原始表达式: {expr}");
        
        // 使用自定义访问者优化常量
        var optimizer = new ConstantFoldingVisitor();
        var optimized = optimizer.Visit(expr);
        
        Console.WriteLine($"优化后表达式: {optimized}");
        
        // 测试执行结果
        var original = expr.Compile();
        var optimizedFunc = ((Expression<Func<int, int>>)optimized).Compile();
        
        Console.WriteLine($"原始结果 f(5): {original(5)}");
        Console.WriteLine($"优化结果 f(5): {optimizedFunc(5)}");
    }
    
    private static void DemonstrateParameterReplacement()
    {
        // 原始表达式: x => x * 2 + 1
        var parameter = Expression.Parameter(typeof(int), "x");
        var body = Expression.Add(
            Expression.Multiply(parameter, Expression.Constant(2)),
            Expression.Constant(1)
        );
        var lambda = Expression.Lambda<Func<int, int>>(body, parameter);
        
        Console.WriteLine($"原始表达式: {lambda}");
        
        // 替换参数为常量值
        var replacer = new ParameterReplacer(parameter, Expression.Constant(10));
        var replaced = replacer.Visit(lambda.Body);
        
        Console.WriteLine($"参数替换后: {replaced}");
        
        // 计算结果
        var result = Expression.Lambda<Func<int>>(replaced).Compile()();
        Console.WriteLine($"计算结果: {result}");
    }
    
    private static void DemonstrateExpressionComposition()
    {
        // 组合两个表达式: f(x) = x * 2, g(x) = x + 1
        // 创建 h(x) = f(g(x)) = (x + 1) * 2
        
        Expression<Func<int, int>> f = x => x * 2;
        Expression<Func<int, int>> g = x => x + 1;
        
        Console.WriteLine($"f(x): {f}");
        Console.WriteLine($"g(x): {g}");
        
        // 手动组合表达式
        var parameter = Expression.Parameter(typeof(int), "x");
        var gBody = new ParameterReplacer(g.Parameters[0], parameter).Visit(g.Body);
        var composedBody = new ParameterReplacer(f.Parameters[0], gBody).Visit(f.Body);
        var composed = Expression.Lambda<Func<int, int>>(composedBody, parameter);
        
        Console.WriteLine($"h(x) = f(g(x)): {composed}");
        
        // 测试组合函数
        var fFunc = f.Compile();
        var gFunc = g.Compile();
        var hFunc = composed.Compile();
        
        int testValue = 5;
        Console.WriteLine($"\n测试值: {testValue}");
        Console.WriteLine($"g({testValue}) = {gFunc(testValue)}");
        Console.WriteLine($"f(g({testValue})) = {fFunc(gFunc(testValue))}");
        Console.WriteLine($"h({testValue}) = {hFunc(testValue)}");
    }
}

// 常量折叠访问者
public class ConstantFoldingVisitor : ExpressionVisitor
{
    protected override Expression VisitBinary(BinaryExpression node)
    {
        var left = Visit(node.Left);
        var right = Visit(node.Right);
        
        // 如果两个操作数都是常量,则计算结果
        if (left is ConstantExpression leftConst && right is ConstantExpression rightConst)
        {
            try
            {
                var leftValue = leftConst.Value;
                var rightValue = rightConst.Value;
                
                object result = node.NodeType switch
                {
                    ExpressionType.Add => (int)leftValue + (int)rightValue,
                    ExpressionType.Subtract => (int)leftValue - (int)rightValue,
                    ExpressionType.Multiply => (int)leftValue * (int)rightValue,
                    ExpressionType.Divide => (int)leftValue / (int)rightValue,
                    _ => null
                };
                
                if (result != null)
                {
                    return Expression.Constant(result, node.Type);
                }
            }
            catch
            {
                // 如果计算失败,返回原始表达式
            }
        }
        
        return Expression.MakeBinary(node.NodeType, left, right);
    }
}

// 参数替换访问者
public class ParameterReplacer : ExpressionVisitor
{
    private readonly ParameterExpression _parameter;
    private readonly Expression _replacement;
    
    public ParameterReplacer(ParameterExpression parameter, Expression replacement)
    {
        _parameter = parameter;
        _replacement = replacement;
    }
    
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == _parameter ? _replacement : node;
    }
}

4. 自定义LINQ扩展方法

4.1 基础扩展方法

public static class CustomLinqExtensions
{
    // 批处理扩展方法
    public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> source, int batchSize)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (batchSize <= 0) throw new ArgumentException("Batch size must be positive", nameof(batchSize));
        
        return BatchImpl(source, batchSize);
    }
    
    private static IEnumerable<IEnumerable<T>> BatchImpl<T>(IEnumerable<T> source, int batchSize)
    {
        var batch = new List<T>(batchSize);
        
        foreach (var item in source)
        {
            batch.Add(item);
            
            if (batch.Count == batchSize)
            {
                yield return batch;
                batch = new List<T>(batchSize);
            }
        }
        
        if (batch.Count > 0)
        {
            yield return batch;
        }
    }
    
    // 窗口函数扩展方法
    public static IEnumerable<IEnumerable<T>> Window<T>(this IEnumerable<T> source, int windowSize)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (windowSize <= 0) throw new ArgumentException("Window size must be positive", nameof(windowSize));
        
        return WindowImpl(source, windowSize);
    }
    
    private static IEnumerable<IEnumerable<T>> WindowImpl<T>(IEnumerable<T> source, int windowSize)
    {
        var window = new Queue<T>(windowSize);
        
        foreach (var item in source)
        {
            window.Enqueue(item);
            
            if (window.Count > windowSize)
            {
                window.Dequeue();
            }
            
            if (window.Count == windowSize)
            {
                yield return window.ToArray();
            }
        }
    }
    
    // 条件聚合扩展方法
    public static TResult AggregateWhile<T, TResult>(
        this IEnumerable<T> source,
        TResult seed,
        Func<TResult, T, TResult> accumulator,
        Func<TResult, T, bool> condition)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (accumulator == null) throw new ArgumentNullException(nameof(accumulator));
        if (condition == null) throw new ArgumentNullException(nameof(condition));
        
        var result = seed;
        
        foreach (var item in source)
        {
            if (!condition(result, item))
                break;
                
            result = accumulator(result, item);
        }
        
        return result;
    }
    
    // 安全的FirstOrDefault扩展
    public static T FirstOrDefault<T>(this IEnumerable<T> source, T defaultValue)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        
        foreach (var item in source)
        {
            return item;
        }
        
        return defaultValue;
    }
    
    // 带索引的Where扩展
    public static IEnumerable<T> WhereWithIndex<T>(this IEnumerable<T> source, Func<T, int, bool> predicate)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (predicate == null) throw new ArgumentNullException(nameof(predicate));
        
        int index = 0;
        foreach (var item in source)
        {
            if (predicate(item, index))
            {
                yield return item;
            }
            index++;
        }
    }
    
    // 递归扩展方法
    public static IEnumerable<T> Traverse<T>(this T root, Func<T, IEnumerable<T>> getChildren)
    {
        if (root == null) yield break;
        if (getChildren == null) throw new ArgumentNullException(nameof(getChildren));
        
        var stack = new Stack<T>();
        stack.Push(root);
        
        while (stack.Count > 0)
        {
            var current = stack.Pop();
            yield return current;
            
            var children = getChildren(current);
            if (children != null)
            {
                foreach (var child in children.Reverse())
                {
                    stack.Push(child);
                }
            }
        }
    }
    
    // 去重扩展方法(基于键)
    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
        
        var seen = new HashSet<TKey>();
        
        foreach (var item in source)
        {
            var key = keySelector(item);
            if (seen.Add(key))
            {
                yield return item;
            }
        }
    }
}

// 扩展方法使用示例
public class CustomLinqDemo
{
    public static void DemonstrateCustomExtensions()
    {
        Console.WriteLine("\n=== 自定义LINQ扩展方法演示 ===");
        
        var numbers = Enumerable.Range(1, 20).ToList();
        Console.WriteLine($"原始数据: [{string.Join(", ", numbers)}]");
        
        Console.WriteLine("\n--- Batch扩展方法 ---");
        var batches = numbers.Batch(5);
        foreach (var batch in batches)
        {
            Console.WriteLine($"批次: [{string.Join(", ", batch)}]");
        }
        
        Console.WriteLine("\n--- Window扩展方法 ---");
        var windows = numbers.Take(10).Window(3);
        foreach (var window in windows)
        {
            Console.WriteLine($"窗口: [{string.Join(", ", window)}]");
        }
        
        Console.WriteLine("\n--- AggregateWhile扩展方法 ---");
        var sumWhileLessThan50 = numbers.AggregateWhile(
            0,
            (acc, x) => acc + x,
            (acc, x) => acc + x <= 50
        );
        Console.WriteLine($"累加直到超过50: {sumWhileLessThan50}");
        
        Console.WriteLine("\n--- WhereWithIndex扩展方法 ---");
        var evenIndexItems = numbers.Take(10).WhereWithIndex((item, index) => index % 2 == 0);
        Console.WriteLine($"偶数索引项: [{string.Join(", ", evenIndexItems)}]");
        
        Console.WriteLine("\n--- DistinctBy扩展方法 ---");
        var students = new[]
        {
            new { Name = "张三", Age = 20 },
            new { Name = "李四", Age = 21 },
            new { Name = "王五", Age = 20 },
            new { Name = "赵六", Age = 22 }
        };
        
        var distinctByAge = students.DistinctBy(s => s.Age);
        Console.WriteLine("按年龄去重:");
        foreach (var student in distinctByAge)
        {
            Console.WriteLine($"  {student.Name} - {student.Age}岁");
        }
        
        Console.WriteLine("\n--- Traverse扩展方法 ---");
        var tree = new TreeNode
        {
            Value = "Root",
            Children = new[]
            {
                new TreeNode
                {
                    Value = "Child1",
                    Children = new[]
                    {
                        new TreeNode { Value = "Grandchild1" },
                        new TreeNode { Value = "Grandchild2" }
                    }
                },
                new TreeNode { Value = "Child2" }
            }
        };
        
        var allNodes = tree.Traverse(node => node.Children ?? Enumerable.Empty<TreeNode>());
        Console.WriteLine($"遍历树节点: [{string.Join(", ", allNodes.Select(n => n.Value))}]");
    }
}

public class TreeNode
{
    public string Value { get; set; }
    public IEnumerable<TreeNode> Children { get; set; }
}

5. LINQ性能优化

5.1 性能分析和优化策略

using System.Diagnostics;

public class LinqPerformanceOptimization
{
    public static void DemonstratePerformanceOptimization()
    {
        Console.WriteLine("\n=== LINQ性能优化演示 ===");
        
        Console.WriteLine("\n--- 延迟执行 vs 立即执行 ---");
        DemonstrateDeferredVsImmediate();
        
        Console.WriteLine("\n--- 查询优化 ---");
        DemonstrateQueryOptimization();
        
        Console.WriteLine("\n--- 内存使用优化 ---");
        DemonstrateMemoryOptimization();
        
        Console.WriteLine("\n--- 并行LINQ性能 ---");
        DemonstrateParallelLinqPerformance();
    }
    
    private static void DemonstrateDeferredVsImmediate()
    {
        var data = Enumerable.Range(1, 1000000).ToList();
        
        // 延迟执行
        var sw = Stopwatch.StartNew();
        var deferredQuery = data.Where(x => x % 2 == 0).Select(x => x * x);
        sw.Stop();
        Console.WriteLine($"延迟查询创建时间: {sw.ElapsedMilliseconds}ms");
        
        // 立即执行
        sw.Restart();
        var immediateQuery = data.Where(x => x % 2 == 0).Select(x => x * x).ToList();
        sw.Stop();
        Console.WriteLine($"立即执行时间: {sw.ElapsedMilliseconds}ms");
        
        // 延迟执行的实际执行
        sw.Restart();
        var deferredResult = deferredQuery.ToList();
        sw.Stop();
        Console.WriteLine($"延迟查询执行时间: {sw.ElapsedMilliseconds}ms");
        
        Console.WriteLine($"结果数量: {immediateQuery.Count} vs {deferredResult.Count}");
    }
    
    private static void DemonstrateQueryOptimization()
    {
        var data = Enumerable.Range(1, 100000)
            .Select(i => new { Id = i, Value = i * 2, Category = i % 10 })
            .ToList();
        
        // 低效查询:多次遍历
        var sw = Stopwatch.StartNew();
        var inefficientResult = data
            .Where(x => x.Category == 5)
            .Where(x => x.Value > 1000)
            .Select(x => x.Id)
            .ToList();
        sw.Stop();
        var inefficientTime = sw.ElapsedMilliseconds;
        
        // 高效查询:单次遍历
        sw.Restart();
        var efficientResult = data
            .Where(x => x.Category == 5 && x.Value > 1000)
            .Select(x => x.Id)
            .ToList();
        sw.Stop();
        var efficientTime = sw.ElapsedMilliseconds;
        
        Console.WriteLine($"低效查询时间: {inefficientTime}ms");
        Console.WriteLine($"高效查询时间: {efficientTime}ms");
        Console.WriteLine($"性能提升: {(double)inefficientTime / efficientTime:F2}x");
        Console.WriteLine($"结果数量: {inefficientResult.Count} vs {efficientResult.Count}");
        
        // 使用索引优化
        var indexedData = data.ToLookup(x => x.Category);
        
        sw.Restart();
        var indexedResult = indexedData[5]
            .Where(x => x.Value > 1000)
            .Select(x => x.Id)
            .ToList();
        sw.Stop();
        var indexedTime = sw.ElapsedMilliseconds;
        
        Console.WriteLine($"索引查询时间: {indexedTime}ms");
        Console.WriteLine($"索引性能提升: {(double)efficientTime / Math.Max(indexedTime, 1):F2}x");
    }
    
    private static void DemonstrateMemoryOptimization()
    {
        // 内存友好的大数据处理
        Console.WriteLine("\n内存使用对比:");
        
        // 方法1:全部加载到内存
        var sw = Stopwatch.StartNew();
        var memoryIntensive = Enumerable.Range(1, 1000000)
            .Where(x => x % 1000 == 0)
            .Select(x => x.ToString())
            .ToList(); // 立即执行,占用内存
        sw.Stop();
        
        Console.WriteLine($"内存密集方法时间: {sw.ElapsedMilliseconds}ms");
        Console.WriteLine($"结果数量: {memoryIntensive.Count}");
        
        // 方法2:流式处理
        sw.Restart();
        var streamingCount = 0;
        foreach (var item in Enumerable.Range(1, 1000000)
            .Where(x => x % 1000 == 0)
            .Select(x => x.ToString()))
        {
            streamingCount++;
            // 处理单个项目,不占用大量内存
        }
        sw.Stop();
        
        Console.WriteLine($"流式处理时间: {sw.ElapsedMilliseconds}ms");
        Console.WriteLine($"处理数量: {streamingCount}");
        
        // 使用yield return的自定义方法
        sw.Restart();
        var yieldCount = ProcessLargeDataset().Count();
        sw.Stop();
        
        Console.WriteLine($"Yield方法时间: {sw.ElapsedMilliseconds}ms");
        Console.WriteLine($"处理数量: {yieldCount}");
    }
    
    private static IEnumerable<string> ProcessLargeDataset()
    {
        for (int i = 1; i <= 1000000; i++)
        {
            if (i % 1000 == 0)
            {
                yield return i.ToString();
            }
        }
    }
    
    private static void DemonstrateParallelLinqPerformance()
    {
        var data = Enumerable.Range(1, 1000000).ToList();
        
        // 串行处理
        var sw = Stopwatch.StartNew();
        var sequentialResult = data
            .Where(x => IsPrime(x))
            .Sum();
        sw.Stop();
        var sequentialTime = sw.ElapsedMilliseconds;
        
        // 并行处理
        sw.Restart();
        var parallelResult = data
            .AsParallel()
            .Where(x => IsPrime(x))
            .Sum();
        sw.Stop();
        var parallelTime = sw.ElapsedMilliseconds;
        
        Console.WriteLine($"串行处理时间: {sequentialTime}ms");
        Console.WriteLine($"并行处理时间: {parallelTime}ms");
        Console.WriteLine($"并行性能提升: {(double)sequentialTime / parallelTime:F2}x");
        Console.WriteLine($"结果: {sequentialResult} vs {parallelResult}");
        
        // 配置并行度
        sw.Restart();
        var configuredParallelResult = data
            .AsParallel()
            .WithDegreeOfParallelism(Environment.ProcessorCount / 2)
            .Where(x => IsPrime(x))
            .Sum();
        sw.Stop();
        var configuredTime = sw.ElapsedMilliseconds;
        
        Console.WriteLine($"配置并行度时间: {configuredTime}ms");
    }
    
    private static bool IsPrime(int number)
    {
        if (number < 2) return false;
        if (number == 2) return true;
        if (number % 2 == 0) return false;
        
        for (int i = 3; i * i <= number; i += 2)
        {
            if (number % i == 0) return false;
        }
        
        return true;
    }
}

5.2 最佳实践和常见陷阱

public class LinqBestPractices
{
    public static void DemonstrateBestPractices()
    {
        Console.WriteLine("\n=== LINQ最佳实践演示 ===");
        
        Console.WriteLine("\n--- 避免多次枚举 ---");
        AvoidMultipleEnumeration();
        
        Console.WriteLine("\n--- 正确使用Any和Count ---");
        UseAnyAndCountCorrectly();
        
        Console.WriteLine("\n--- 选择合适的集合类型 ---");
        ChooseRightCollectionType();
        
        Console.WriteLine("\n--- 异常处理最佳实践 ---");
        HandleExceptionsCorrectly();
    }
    
    private static void AvoidMultipleEnumeration()
    {
        // 错误做法:多次枚举
        var expensiveQuery = GetExpensiveData().Where(x => x > 100);
        
        Console.WriteLine("错误做法 - 多次枚举:");
        var sw = Stopwatch.StartNew();
        
        if (expensiveQuery.Any())
        {
            Console.WriteLine($"找到 {expensiveQuery.Count()} 个结果");
            Console.WriteLine($"第一个结果: {expensiveQuery.First()}");
        }
        
        sw.Stop();
        Console.WriteLine($"多次枚举时间: {sw.ElapsedMilliseconds}ms");
        
        // 正确做法:缓存结果
        sw.Restart();
        var cachedResults = GetExpensiveData().Where(x => x > 100).ToList();
        
        if (cachedResults.Any())
        {
            Console.WriteLine($"\n正确做法 - 缓存结果:");
            Console.WriteLine($"找到 {cachedResults.Count} 个结果");
            Console.WriteLine($"第一个结果: {cachedResults.First()}");
        }
        
        sw.Stop();
        Console.WriteLine($"缓存结果时间: {sw.ElapsedMilliseconds}ms");
    }
    
    private static IEnumerable<int> GetExpensiveData()
    {
        Console.WriteLine("  执行昂贵的数据获取操作...");
        Thread.Sleep(100); // 模拟昂贵操作
        return Enumerable.Range(1, 1000);
    }
    
    private static void UseAnyAndCountCorrectly()
    {
        var data = Enumerable.Range(1, 1000000).ToList();
        
        // 检查是否存在元素
        var sw = Stopwatch.StartNew();
        bool hasEvenNumbers1 = data.Where(x => x % 2 == 0).Count() > 0; // 错误
        sw.Stop();
        var wrongTime = sw.ElapsedMilliseconds;
        
        sw.Restart();
        bool hasEvenNumbers2 = data.Any(x => x % 2 == 0); // 正确
        sw.Stop();
        var rightTime = sw.ElapsedMilliseconds;
        
        Console.WriteLine($"使用Count() > 0: {wrongTime}ms");
        Console.WriteLine($"使用Any(): {rightTime}ms");
        Console.WriteLine($"性能提升: {(double)wrongTime / Math.Max(rightTime, 1):F2}x");
        
        // 检查特定数量
        sw.Restart();
        bool hasManyItems1 = data.Where(x => x % 100 == 0).Count() >= 5; // 可以接受
        sw.Stop();
        var countTime = sw.ElapsedMilliseconds;
        
        sw.Restart();
        bool hasManyItems2 = data.Where(x => x % 100 == 0).Skip(4).Any(); // 更高效
        sw.Stop();
        var skipAnyTime = sw.ElapsedMilliseconds;
        
        Console.WriteLine($"\n使用Count() >= 5: {countTime}ms");
        Console.WriteLine($"使用Skip(4).Any(): {skipAnyTime}ms");
    }
    
    private static void ChooseRightCollectionType()
    {
        var data = Enumerable.Range(1, 100000).ToList();
        
        // 频繁查找 - 使用HashSet
        var sw = Stopwatch.StartNew();
        var listLookup = data.ToList();
        bool found1 = listLookup.Contains(99999);
        sw.Stop();
        var listTime = sw.ElapsedMilliseconds;
        
        sw.Restart();
        var hashSetLookup = data.ToHashSet();
        bool found2 = hashSetLookup.Contains(99999);
        sw.Stop();
        var hashSetTime = sw.ElapsedMilliseconds;
        
        Console.WriteLine($"List查找时间: {listTime}ms");
        Console.WriteLine($"HashSet查找时间: {hashSetTime}ms");
        
        // 分组查找 - 使用Lookup
        sw.Restart();
        var groupedList = data.GroupBy(x => x % 10).ToList();
        var group1 = groupedList.First(g => g.Key == 5).ToList();
        sw.Stop();
        var groupByTime = sw.ElapsedMilliseconds;
        
        sw.Restart();
        var lookup = data.ToLookup(x => x % 10);
        var group2 = lookup[5].ToList();
        sw.Stop();
        var lookupTime = sw.ElapsedMilliseconds;
        
        Console.WriteLine($"\nGroupBy查找时间: {groupByTime}ms");
        Console.WriteLine($"Lookup查找时间: {lookupTime}ms");
    }
    
    private static void HandleExceptionsCorrectly()
    {
        var data = new[] { "1", "2", "abc", "4", "5" };
        
        // 错误做法:异常会中断整个查询
        try
        {
            var wrongResult = data.Select(int.Parse).Sum();
            Console.WriteLine($"错误做法结果: {wrongResult}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"错误做法异常: {ex.Message}");
        }
        
        // 正确做法1:使用TryParse
        var correctResult1 = data
            .Select(s => int.TryParse(s, out int value) ? value : (int?)null)
            .Where(x => x.HasValue)
            .Sum(x => x.Value);
        
        Console.WriteLine($"正确做法1结果: {correctResult1}");
        
        // 正确做法2:使用Where过滤
        var correctResult2 = data
            .Where(s => int.TryParse(s, out _))
            .Select(int.Parse)
            .Sum();
        
        Console.WriteLine($"正确做法2结果: {correctResult2}");
        
        // 正确做法3:使用自定义扩展方法
        var correctResult3 = data.TrySelect(int.Parse).Sum();
        Console.WriteLine($"正确做法3结果: {correctResult3}");
    }
}

// 安全转换扩展方法
public static class SafeLinqExtensions
{
    public static IEnumerable<TResult> TrySelect<TSource, TResult>(
        this IEnumerable<TSource> source,
        Func<TSource, TResult> selector)
    {
        foreach (var item in source)
        {
            TResult result;
            try
            {
                result = selector(item);
                yield return result;
            }
            catch
            {
                // 忽略转换失败的项目
                continue;
            }
        }
    }
}

6. 实践练习

6.1 数据分析系统

public class SalesRecord
{
    public int Id { get; set; }
    public DateTime Date { get; set; }
    public string Product { get; set; }
    public string Category { get; set; }
    public decimal Amount { get; set; }
    public string Region { get; set; }
    public string SalesPerson { get; set; }
}

public class DataAnalysisSystem
{
    private readonly List<SalesRecord> _salesData;
    
    public DataAnalysisSystem()
    {
        _salesData = GenerateSampleData();
    }
    
    public void RunAnalysis()
    {
        Console.WriteLine("\n=== 数据分析系统演示 ===");
        
        Console.WriteLine("\n--- 基础统计 ---");
        BasicStatistics();
        
        Console.WriteLine("\n--- 时间序列分析 ---");
        TimeSeriesAnalysis();
        
        Console.WriteLine("\n--- 地区分析 ---");
        RegionalAnalysis();
        
        Console.WriteLine("\n--- 销售人员绩效 ---");
        SalesPersonPerformance();
        
        Console.WriteLine("\n--- 产品分析 ---");
        ProductAnalysis();
    }
    
    private void BasicStatistics()
    {
        var totalSales = _salesData.Sum(s => s.Amount);
        var averageSale = _salesData.Average(s => s.Amount);
        var maxSale = _salesData.Max(s => s.Amount);
        var minSale = _salesData.Min(s => s.Amount);
        var totalRecords = _salesData.Count;
        
        Console.WriteLine($"总销售额: {totalSales:C}");
        Console.WriteLine($"平均销售额: {averageSale:C}");
        Console.WriteLine($"最大单笔销售: {maxSale:C}");
        Console.WriteLine($"最小单笔销售: {minSale:C}");
        Console.WriteLine($"总记录数: {totalRecords}");
        
        // 按类别统计
        var categoryStats = _salesData
            .GroupBy(s => s.Category)
            .Select(g => new
            {
                Category = g.Key,
                TotalSales = g.Sum(s => s.Amount),
                Count = g.Count(),
                AverageSale = g.Average(s => s.Amount)
            })
            .OrderByDescending(x => x.TotalSales);
        
        Console.WriteLine("\n按类别统计:");
        foreach (var stat in categoryStats)
        {
            Console.WriteLine($"  {stat.Category}: {stat.TotalSales:C} ({stat.Count}笔, 平均{stat.AverageSale:C})");
        }
    }
    
    private void TimeSeriesAnalysis()
    {
        // 按月统计
        var monthlySales = _salesData
            .GroupBy(s => new { s.Date.Year, s.Date.Month })
            .Select(g => new
            {
                Year = g.Key.Year,
                Month = g.Key.Month,
                TotalSales = g.Sum(s => s.Amount),
                Count = g.Count()
            })
            .OrderBy(x => x.Year).ThenBy(x => x.Month);
        
        Console.WriteLine("月度销售趋势:");
        foreach (var month in monthlySales)
        {
            Console.WriteLine($"  {month.Year}-{month.Month:D2}: {month.TotalSales:C} ({month.Count}笔)");
        }
        
        // 计算增长率
        var monthlyGrowth = monthlySales
            .Zip(monthlySales.Skip(1), (prev, curr) => new
            {
                Month = $"{curr.Year}-{curr.Month:D2}",
                GrowthRate = (curr.TotalSales - prev.TotalSales) / prev.TotalSales * 100
            });
        
        Console.WriteLine("\n月度增长率:");
        foreach (var growth in monthlyGrowth)
        {
            Console.WriteLine($"  {growth.Month}: {growth.GrowthRate:F2}%");
        }
    }
    
    private void RegionalAnalysis()
    {
        var regionalStats = _salesData
            .GroupBy(s => s.Region)
            .Select(g => new
            {
                Region = g.Key,
                TotalSales = g.Sum(s => s.Amount),
                AverageSale = g.Average(s => s.Amount),
                TopProduct = g.GroupBy(s => s.Product)
                    .OrderByDescending(pg => pg.Sum(s => s.Amount))
                    .First().Key,
                SalesPersonCount = g.Select(s => s.SalesPerson).Distinct().Count()
            })
            .OrderByDescending(x => x.TotalSales);
        
        Console.WriteLine("地区销售分析:");
        foreach (var region in regionalStats)
        {
            Console.WriteLine($"  {region.Region}:");
            Console.WriteLine($"    总销售额: {region.TotalSales:C}");
            Console.WriteLine($"    平均销售额: {region.AverageSale:C}");
            Console.WriteLine($"    热销产品: {region.TopProduct}");
            Console.WriteLine($"    销售人员数: {region.SalesPersonCount}");
        }
    }
    
    private void SalesPersonPerformance()
    {
        var performanceStats = _salesData
            .GroupBy(s => s.SalesPerson)
            .Select(g => new
            {
                SalesPerson = g.Key,
                TotalSales = g.Sum(s => s.Amount),
                SalesCount = g.Count(),
                AverageSale = g.Average(s => s.Amount),
                BestMonth = g.GroupBy(s => new { s.Date.Year, s.Date.Month })
                    .OrderByDescending(mg => mg.Sum(s => s.Amount))
                    .First(),
                ProductDiversity = g.Select(s => s.Product).Distinct().Count()
            })
            .OrderByDescending(x => x.TotalSales)
            .Take(10);
        
        Console.WriteLine("销售人员绩效 (前10名):");
        foreach (var perf in performanceStats)
        {
            Console.WriteLine($"  {perf.SalesPerson}:");
            Console.WriteLine($"    总销售额: {perf.TotalSales:C}");
            Console.WriteLine($"    销售笔数: {perf.SalesCount}");
            Console.WriteLine($"    平均单笔: {perf.AverageSale:C}");
            Console.WriteLine($"    最佳月份: {perf.BestMonth.Key.Year}-{perf.BestMonth.Key.Month:D2} ({perf.BestMonth.Sum(s => s.Amount):C})");
            Console.WriteLine($"    产品多样性: {perf.ProductDiversity}种产品");
        }
    }
    
    private void ProductAnalysis()
    {
        // 产品生命周期分析
        var productLifecycle = _salesData
            .GroupBy(s => s.Product)
            .Select(g => new
            {
                Product = g.Key,
                FirstSale = g.Min(s => s.Date),
                LastSale = g.Max(s => s.Date),
                TotalSales = g.Sum(s => s.Amount),
                SalesCount = g.Count(),
                PeakMonth = g.GroupBy(s => new { s.Date.Year, s.Date.Month })
                    .OrderByDescending(mg => mg.Sum(s => s.Amount))
                    .First()
            })
            .OrderByDescending(x => x.TotalSales)
            .Take(5);
        
        Console.WriteLine("产品生命周期分析 (前5名):");
        foreach (var product in productLifecycle)
        {
            var lifecycle = (product.LastSale - product.FirstSale).Days;
            Console.WriteLine($"  {product.Product}:");
            Console.WriteLine($"    总销售额: {product.TotalSales:C}");
            Console.WriteLine($"    生命周期: {lifecycle}天");
            Console.WriteLine($"    首次销售: {product.FirstSale:yyyy-MM-dd}");
            Console.WriteLine($"    最后销售: {product.LastSale:yyyy-MM-dd}");
            Console.WriteLine($"    销售高峰: {product.PeakMonth.Key.Year}-{product.PeakMonth.Key.Month:D2} ({product.PeakMonth.Sum(s => s.Amount):C})");
        }
        
        // 产品关联分析
        var productPairs = _salesData
            .GroupBy(s => new { s.SalesPerson, Date = s.Date.Date })
            .Where(g => g.Select(s => s.Product).Distinct().Count() > 1)
            .SelectMany(g => 
                from p1 in g.Select(s => s.Product).Distinct()
                from p2 in g.Select(s => s.Product).Distinct()
                where string.Compare(p1, p2) < 0
                select new { Product1 = p1, Product2 = p2 })
            .GroupBy(pair => new { pair.Product1, pair.Product2 })
            .Select(g => new
            {
                Product1 = g.Key.Product1,
                Product2 = g.Key.Product2,
                CoOccurrence = g.Count()
            })
            .OrderByDescending(x => x.CoOccurrence)
            .Take(5);
        
        Console.WriteLine("\n产品关联分析 (经常一起销售的产品):");
        foreach (var pair in productPairs)
        {
            Console.WriteLine($"  {pair.Product1} + {pair.Product2}: {pair.CoOccurrence}次");
        }
    }
    
    private List<SalesRecord> GenerateSampleData()
    {
        var random = new Random(42);
        var products = new[] { "笔记本电脑", "台式机", "显示器", "键盘", "鼠标", "耳机", "音响", "摄像头" };
        var categories = new[] { "电脑", "配件", "外设" };
        var regions = new[] { "华北", "华东", "华南", "西南", "东北" };
        var salesPeople = new[] { "张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十" };
        
        var data = new List<SalesRecord>();
        var startDate = DateTime.Now.AddMonths(-12);
        
        for (int i = 0; i < 10000; i++)
        {
            var product = products[random.Next(products.Length)];
            var category = product switch
            {
                "笔记本电脑" or "台式机" => "电脑",
                "显示器" => "配件",
                _ => "外设"
            };
            
            data.Add(new SalesRecord
            {
                Id = i + 1,
                Date = startDate.AddDays(random.Next(365)),
                Product = product,
                Category = category,
                Amount = random.Next(100, 5000),
                Region = regions[random.Next(regions.Length)],
                SalesPerson = salesPeople[random.Next(salesPeople.Length)]
            });
        }
        
        return data;
    }
}

6.2 动态查询构建器

public class DynamicQueryBuilder<T>
{
    private IQueryable<T> _query;
    private readonly List<Expression<Func<T, bool>>> _filters;
    private readonly List<(Expression<Func<T, object>> KeySelector, bool Descending)> _orderBy;
    
    public DynamicQueryBuilder(IQueryable<T> source)
    {
        _query = source;
        _filters = new List<Expression<Func<T, bool>>>();
        _orderBy = new List<(Expression<Func<T, object>>, bool)>();
    }
    
    public DynamicQueryBuilder<T> Where(Expression<Func<T, bool>> predicate)
    {
        _filters.Add(predicate);
        return this;
    }
    
    public DynamicQueryBuilder<T> WhereIf(bool condition, Expression<Func<T, bool>> predicate)
    {
        if (condition)
        {
            _filters.Add(predicate);
        }
        return this;
    }
    
    public DynamicQueryBuilder<T> OrderBy(Expression<Func<T, object>> keySelector)
    {
        _orderBy.Add((keySelector, false));
        return this;
    }
    
    public DynamicQueryBuilder<T> OrderByDescending(Expression<Func<T, object>> keySelector)
    {
        _orderBy.Add((keySelector, true));
        return this;
    }
    
    public DynamicQueryBuilder<T> WherePropertyEquals(string propertyName, object value)
    {
        var parameter = Expression.Parameter(typeof(T), "x");
        var property = Expression.Property(parameter, propertyName);
        var constant = Expression.Constant(value);
        var equals = Expression.Equal(property, constant);
        var lambda = Expression.Lambda<Func<T, bool>>(equals, parameter);
        
        _filters.Add(lambda);
        return this;
    }
    
    public DynamicQueryBuilder<T> WherePropertyContains(string propertyName, string value)
    {
        if (string.IsNullOrEmpty(value)) return this;
        
        var parameter = Expression.Parameter(typeof(T), "x");
        var property = Expression.Property(parameter, propertyName);
        var constant = Expression.Constant(value);
        var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        var contains = Expression.Call(property, containsMethod, constant);
        var lambda = Expression.Lambda<Func<T, bool>>(contains, parameter);
        
        _filters.Add(lambda);
        return this;
    }
    
    public DynamicQueryBuilder<T> WherePropertyInRange<TProperty>(string propertyName, TProperty? min, TProperty? max)
        where TProperty : struct, IComparable<TProperty>
    {
        var parameter = Expression.Parameter(typeof(T), "x");
        var property = Expression.Property(parameter, propertyName);
        
        Expression condition = null;
        
        if (min.HasValue)
        {
            var minConstant = Expression.Constant(min.Value);
            var greaterEqual = Expression.GreaterThanOrEqual(property, minConstant);
            condition = condition == null ? greaterEqual : Expression.AndAlso(condition, greaterEqual);
        }
        
        if (max.HasValue)
        {
            var maxConstant = Expression.Constant(max.Value);
            var lessEqual = Expression.LessThanOrEqual(property, maxConstant);
            condition = condition == null ? lessEqual : Expression.AndAlso(condition, lessEqual);
        }
        
        if (condition != null)
        {
            var lambda = Expression.Lambda<Func<T, bool>>(condition, parameter);
            _filters.Add(lambda);
        }
        
        return this;
    }
    
    public IQueryable<T> Build()
    {
        var result = _query;
        
        // 应用所有过滤条件
        foreach (var filter in _filters)
        {
            result = result.Where(filter);
        }
        
        // 应用排序
        if (_orderBy.Any())
        {
            var firstOrder = _orderBy.First();
            result = firstOrder.Descending 
                ? result.OrderByDescending(firstOrder.KeySelector)
                : result.OrderBy(firstOrder.KeySelector);
            
            foreach (var order in _orderBy.Skip(1))
            {
                result = order.Descending
                    ? ((IOrderedQueryable<T>)result).ThenByDescending(order.KeySelector)
                    : ((IOrderedQueryable<T>)result).ThenBy(order.KeySelector);
            }
        }
        
        return result;
    }
    
    public List<T> ToList() => Build().ToList();
    public T[] ToArray() => Build().ToArray();
    public T First() => Build().First();
    public T FirstOrDefault() => Build().FirstOrDefault();
    public int Count() => Build().Count();
    public bool Any() => Build().Any();
}

// 使用示例
public class DynamicQueryDemo
{
    public static void DemonstrateDynamicQuery()
    {
        Console.WriteLine("\n=== 动态查询构建器演示 ===");
        
        var students = new List<Student>
        {
            new Student { Id = 1, Name = "张三", Age = 20, Major = "计算机科学", GPA = 3.8 },
            new Student { Id = 2, Name = "李四", Age = 21, Major = "软件工程", GPA = 3.6 },
            new Student { Id = 3, Name = "王五", Age = 19, Major = "计算机科学", GPA = 3.9 },
            new Student { Id = 4, Name = "赵六", Age = 22, Major = "信息系统", GPA = 3.4 },
            new Student { Id = 5, Name = "钱七", Age = 20, Major = "软件工程", GPA = 3.7 }
        }.AsQueryable();
        
        // 动态构建查询
        var queryBuilder = new DynamicQueryBuilder<Student>(students);
        
        // 模拟用户输入的查询条件
        string nameFilter = "";
        string majorFilter = "计算机科学";
        int? minAge = 19;
        int? maxAge = 21;
        double? minGPA = 3.7;
        
        var result = queryBuilder
            .WhereIf(!string.IsNullOrEmpty(nameFilter), s => s.Name.Contains(nameFilter))
            .WhereIf(!string.IsNullOrEmpty(majorFilter), s => s.Major == majorFilter)
            .WherePropertyInRange(nameof(Student.Age), minAge, maxAge)
            .WherePropertyInRange(nameof(Student.GPA), minGPA, null)
            .OrderByDescending(s => s.GPA)
            .ToList();
        
        Console.WriteLine("查询结果:");
        foreach (var student in result)
        {
            Console.WriteLine($"  {student.Name} - {student.Major} - {student.Age}岁 - GPA: {student.GPA}");
        }
        
        // 使用属性名动态查询
        var dynamicResult = new DynamicQueryBuilder<Student>(students)
            .WherePropertyEquals(nameof(Student.Major), "软件工程")
            .WherePropertyContains(nameof(Student.Name), "")
            .OrderBy(s => s.Name)
            .ToList();
        
        Console.WriteLine("\n动态属性查询结果:");
        foreach (var student in dynamicResult)
        {
            Console.WriteLine($"  {student.Name} - {student.Major}");
        }
    }
}

7. 总结

本章深入介绍了LINQ和表达式树的核心概念和实际应用:

核心概念

  • LINQ基础:查询语法vs方法语法、延迟执行vs立即执行
  • LINQ to Objects:过滤、投影、排序、分组、连接等操作
  • 表达式树:构建、分析、修改和转换表达式树
  • 自定义扩展:创建自定义LINQ扩展方法

重要技能

  • 熟练使用各种LINQ操作符进行数据查询和处理
  • 理解延迟执行的机制和性能影响
  • 掌握表达式树的构建和操作技巧
  • 能够创建自定义LINQ扩展方法
  • 掌握LINQ性能优化技巧

最佳实践

  • 避免多次枚举,适当使用缓存
  • 正确使用Any()和Count()方法
  • 选择合适的集合类型进行查询
  • 合理使用并行LINQ提升性能
  • 正确处理查询中的异常情况

实际应用

  • 数据分析和报表生成
  • 动态查询构建
  • 复杂的业务逻辑处理
  • 性能敏感的数据处理场景

LINQ和表达式树是.NET平台上强大的数据处理工具,掌握这些技术能够显著提高开发效率和代码质量。下一章我们将学习文件I/O和序列化。

2.2 排序和分组操作

public class LinqSortingGrouping
{
    public static void DemonstrateSortingGrouping()
    {
        Console.WriteLine("\n=== LINQ排序和分组演示 ===");
        
        var students = GetSampleStudents();
        
        Console.WriteLine("\n--- 排序操作 ---");
        DemonstrateSorting(students);
        
        Console.WriteLine("\n--- 分组操作 ---");
        DemonstrateGrouping(students);
        
        Console.WriteLine("\n--- 复杂分组和排序 ---");
        DemonstrateComplexGrouping(students);
    }
    
    private static List<Student> GetSampleStudents()
    {
        return new List<Student>
        {
            new Student { Id = 1, Name = "张三", Age = 20, Major = "计算机科学", GPA = 3.8 },
            new Student { Id = 2, Name = "李四", Age = 22, Major = "软件工程", GPA = 3.6 },
            new Student { Id = 3, Name = "王五", Age = 19, Major = "计算机科学", GPA = 3.9 },
            new Student { Id = 4, Name = "赵六", Age = 21, Major = "信息系统", GPA = 3.4 },
            new Student { Id = 5, Name = "钱七", Age = 23, Major = "软件工程", GPA = 3.7 },
            new Student { Id = 6, Name = "孙八", Age = 20, Major = "计算机科学", GPA = 3.5 },
            new Student { Id = 7, Name = "周九", Age = 22, Major = "信息系统", GPA = 3.8 },
            new Student { Id = 8, Name = "吴十", Age = 21, Major = "软件工程", GPA = 3.9 }
        };
    }
    
    private static void DemonstrateSorting(List<Student> students)
    {
        // 单字段升序排序
        var sortedByAge = students.OrderBy(s => s.Age);
        Console.WriteLine("按年龄升序排序:");
        foreach (var student in sortedByAge)
        {
            Console.WriteLine($"  {student.Name} - 年龄: {student.Age}");
        }
        
        // 单字段降序排序
        var sortedByGPA = students.OrderByDescending(s => s.GPA);
        Console.WriteLine("\n按GPA降序排序:");
        foreach (var student in sortedByGPA)
        {
            Console.WriteLine($"  {student.Name} - GPA: {student.GPA:F2}");
        }
        
        // 多字段排序
        var multiSort = students
            .OrderBy(s => s.Major)           // 首先按专业排序
            .ThenByDescending(s => s.GPA)    // 然后按GPA降序
            .ThenBy(s => s.Age);             // 最后按年龄升序
        
        Console.WriteLine("\n多字段排序(专业升序 -> GPA降序 -> 年龄升序):");
        foreach (var student in multiSort)
        {
            Console.WriteLine($"  {student.Major} | {student.Name} - GPA: {student.GPA:F2}, 年龄: {student.Age}");
        }
        
        // 自定义比较器排序
        var customSort = students.OrderBy(s => s.Name, StringComparer.OrdinalIgnoreCase);
        Console.WriteLine("\n按姓名排序(忽略大小写):");
        foreach (var student in customSort)
        {
            Console.WriteLine($"  {student.Name}");
        }
    }
    
    private static void DemonstrateGrouping(List<Student> students)
    {
        // 按单个字段分组
        var groupedByMajor = students.GroupBy(s => s.Major);
        Console.WriteLine("按专业分组:");
        foreach (var group in groupedByMajor)
        {
            Console.WriteLine($"  {group.Key} ({group.Count()}人):");
            foreach (var student in group)
            {
                Console.WriteLine($"    {student.Name} - GPA: {student.GPA:F2}");
            }
        }
        
        // 按多个字段分组
        var groupedByMajorAndAge = students.GroupBy(s => new { s.Major, AgeGroup = s.Age < 21 ? "年轻" : "成熟" });
        Console.WriteLine("\n按专业和年龄组分组:");
        foreach (var group in groupedByMajorAndAge)
        {
            Console.WriteLine($"  {group.Key.Major} - {group.Key.AgeGroup} ({group.Count()}人):");
            foreach (var student in group)
            {
                Console.WriteLine($"    {student.Name} - 年龄: {student.Age}");
            }
        }
        
        // 分组后的聚合操作
        var majorStatistics = students
            .GroupBy(s => s.Major)
            .Select(g => new
            {
                Major = g.Key,
                Count = g.Count(),
                AverageGPA = g.Average(s => s.GPA),
                MaxGPA = g.Max(s => s.GPA),
                MinGPA = g.Min(s => s.GPA),
                Students = g.Select(s => s.Name).ToList()
            });
        
        Console.WriteLine("\n专业统计信息:");
        foreach (var stat in majorStatistics)
        {
            Console.WriteLine($"  {stat.Major}:");
            Console.WriteLine($"    人数: {stat.Count}");
            Console.WriteLine($"    平均GPA: {stat.AverageGPA:F2}");
            Console.WriteLine($"    最高GPA: {stat.MaxGPA:F2}");
            Console.WriteLine($"    最低GPA: {stat.MinGPA:F2}");
            Console.WriteLine($"    学生: [{string.Join(", ", stat.Students)}]");
        }
    }
    
    private static void DemonstrateComplexGrouping(List<Student> students)
    {
        // 复杂分组:按GPA等级分组
        var groupedByGrade = students
            .GroupBy(s => s.GPA >= 3.8 ? "优秀" : s.GPA >= 3.6 ? "良好" : "一般")
            .OrderByDescending(g => g.Key); // 按等级排序
        
        Console.WriteLine("按成绩等级分组:");
        foreach (var group in groupedByGrade)
        {
            Console.WriteLine($"  {group.Key} ({group.Count()}人):");
            var sortedStudents = group.OrderByDescending(s => s.GPA);
            foreach (var student in sortedStudents)
            {
                Console.WriteLine($"    {student.Name} ({student.Major}) - GPA: {student.GPA:F2}");
            }
        }
        
        // 嵌套分组:先按专业分组,再按年龄分组
        var nestedGrouping = students
            .GroupBy(s => s.Major)
            .Select(majorGroup => new
            {
                Major = majorGroup.Key,
                AgeGroups = majorGroup.GroupBy(s => s.Age < 21 ? "年轻" : "成熟")
                    .Select(ageGroup => new
                    {
                        AgeGroup = ageGroup.Key,
                        Students = ageGroup.OrderByDescending(s => s.GPA).ToList()
                    })
            });
        
        Console.WriteLine("\n嵌套分组(专业 -> 年龄组):");
        foreach (var majorGroup in nestedGrouping)
        {
            Console.WriteLine($"  {majorGroup.Major}:");
            foreach (var ageGroup in majorGroup.AgeGroups)
            {
                Console.WriteLine($"    {ageGroup.AgeGroup} ({ageGroup.Students.Count}人):");
                foreach (var student in ageGroup.Students)
                {
                    Console.WriteLine($"      {student.Name} - GPA: {student.GPA:F2}, 年龄: {student.Age}");
                }
            }
        }
        
        // 分组后的复杂查询:找出每个专业GPA前2名的学生
        var topStudentsByMajor = students
            .GroupBy(s => s.Major)
            .SelectMany(g => g.OrderByDescending(s => s.GPA).Take(2)
                .Select((student, index) => new
                {
                    Major = g.Key,
                    Rank = index + 1,
                    Student = student
                }));
        
        Console.WriteLine("\n每个专业前2名学生:");
        foreach (var item in topStudentsByMajor.OrderBy(x => x.Major).ThenBy(x => x.Rank))
        {
            Console.WriteLine($"  {item.Major} 第{item.Rank}名: {item.Student.Name} - GPA: {item.Student.GPA:F2}");
        }
    }
}