LINQ语言集成查询是一系列直接将查询功能集成到 C# 语言的技术统称。数据查询历来都表示为简单的字符串,没有编译时类型检查或 IntelliSense 支持。此外,需要针对每种类型的数据源了解不同的查询语言:SQL 数据库、XML 文档、各种 Web 服务等。然而,LINQ的出现改变了这一现状,它使查询成为了与类、方法和事件同等重要的高级语言构造。通过LINQ,开发者能够以声明性的方式查询和操作数据,极大地提高了开发效率和代码的可维护性。
ToList()
、ToArray()
、ToDictionary()
、FirstOrDefault()
等方法可立即执行。LINQ to Objects、LINQ to XML、LINQ to SQL、LINQ to Entities(Entity Framework)
等。 public class StudentInfo
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public DateTime Birthday { get; set; }
public int ClassID { get; set; }
public string Address { get; set; }
public List<Course> Courses { get; set; } = new List<Course>();
}
public class Course
{
public int CourseID { get; set; }
public string CourseName { get; set; }
}
static List<StudentInfo> students = new List<StudentInfo>
{
new StudentInfo
{
StudentID=1,
StudentName="大姚",
Birthday=Convert.ToDateTime("1997-10-25"),
ClassID=101,
Courses = new List<Course>
{
new Course { CourseID = 101, CourseName = "语文" },
new Course { CourseID = 102, CourseName = "数学" }
}
},
new StudentInfo
{
StudentID=2,
StudentName="李四",
Birthday=Convert.ToDateTime("1998-10-25"),
ClassID=101,
Courses = new List<Course>
{
new Course { CourseID = 101, CourseName = "语文" },
new Course { CourseID = 102, CourseName = "数学" }
}
},
new StudentInfo
{
StudentID=3,
StudentName="王五",
Birthday=Convert.ToDateTime("1999-10-25"),
ClassID=102,
Address="广州",
Courses = new List<Course>
{
new Course { CourseID = 101, CourseName = "语文" },
new Course { CourseID = 102, CourseName = "数学" }
}
},
new StudentInfo
{
StudentID=4,
StudentName="时光者",
Birthday=Convert.ToDateTime("1999-11-25"),
ClassID=102,
Address="深圳" ,
Courses = new List<Course>
{
new Course { CourseID = 104, CourseName = "历史" },
new Course { CourseID = 103, CourseName = "地理" }
}
}
};
展平
为一个集合。 var femaleStudents = students.Where(s => s.StudentName == "时光者");
var studentNames = students.Select(s => s.StudentName);
// 使用SelectMany展平所有学生的课程列表
var allCourses = students.SelectMany(student => student.Courses).ToList();
// 输出所有课程的名称
foreach (var course in allCourses)
{
Console.WriteLine(course.CourseName);
}
IEnumerable<T>
接口的集合转换为一个List<T>
类型的对象,属于将集合转换为特定类型列表的方法。IEnumerable<T>
接口的集合转换为一个数组,属于将集合转换为数组类型的方法。IEnumerable<T>
集合转换为一个Dictionary<TKey,TValue>
键值对集合(字典)的方法,注意 ToDictionary 要求键唯一,否则抛出异常。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);
var firstStudent = students.First();
var firstAdult = students.FirstOrDefault(s => s.Birthday <= DateTime.Now.AddYears(-18));
var onlyWangWu = students.Single(s => s.StudentName == "王五");
var wangWuOrDefault = students.SingleOrDefault(s => s.StudentName == "王六");
var lastStudent = students.Last();
var lastAdult = students.LastOrDefault(s => s.Birthday <= DateTime.Now.AddYears(-18));
var secondStudent = students.ElementAt(1);
var tenthStudentOrDefault = students.ElementAtOrDefault(9);
var nonEmptyStudents = students.DefaultIfEmpty(new StudentInfo { StudentID = 0, StudentName = "默认Student", Address = "默认" });
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);
int studentCount = students.Count();
int totalClassID = students.Sum(s => s.ClassID);
double averageAge = students.Average(s => DateTime.Now.Year - s.Birthday.Year);
int minClassID = students.Min(s => s.ClassID);
int maxClassID = students.Max(s => s.ClassID);
string concatenatedNames = students.Aggregate("", (acc, s) => acc == "" ? s.StudentName : acc + ", " + s.StudentName);
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 });
var groupedByClassID = students.GroupBy(s => s.ClassID);
foreach (var group in groupedByClassID)
{
Console.WriteLine($"班级ID: {group.Key}");
foreach (var student in group)
{
Console.WriteLine($" 学生姓名: {student.StudentName}");
}
}
// 连接两个集合(内连接查询)
var otherStudent = new List<StudentInfo>
{
new StudentInfo
{
StudentID=4,
StudentName="摇一摇",
Birthday=Convert.ToDateTime("1997-10-25"),
ClassID=101,
Courses = new List<Course>
{
new Course { CourseID = 101, CourseName = "语文" },
new Course { CourseID = 102, CourseName = "数学" }
}
}
};
var listJoin = students.Join(
otherStudent, // 要连接的第二个集合
s1 => s1.StudentID, // 从第一个集合中提取键
s2 => s2.StudentID, // 从第二个集合中提取键
(s1, s2) => new // 结果选择器,指定如何从两个匹配元素创建结果
{
StudentID = s1.StudentID,
StudentName = s1.StudentName,
Birthday = s1.Birthday,
ClassID = s1.ClassID,
Address = s1.Address,
Courses = s1.Courses,
OtherStudentName = s2.StudentName
});
//使用 GroupJoin 方法实现两个集合的左连接(Left Join)
//目标:获取所有课程及选修学生(即使无人选修也要显示课程)
var courseStudentGroups = courses.GroupJoin(
students.SelectMany(
student => student.Courses,
(student, course) => new { Student = student, Course = course }
),
course => course.CourseID,
studentCoursePair => studentCoursePair.Course.CourseID,
// 结果投影:生成课程名称及对应的学生列表
(course, matchedStudents) => new
{
CourseName = course.CourseName,
Students = matchedStudents
.Select(pair => pair.Student.StudentName)
.DefaultIfEmpty("(无学生)")
.ToList()
}
).ToList();
// 输出结果
foreach (var group in courseStudentGroups)
{
Console.WriteLine("-------------------");
Console.WriteLine($"课程:{group.CourseName}");
Console.WriteLine($"选修学生:{string.Join(", ", group.Students)}");
Console.WriteLine("-------------------");
}
var skippedStudents = students.Skip(1);
var takenStudents = students.Take(2);
//数据分页查询(Skip + Take)
int pageNumber = 2;
int pageSize = 10;
var pagedUsers = skippedStudents
.OrderBy(u => u.ClassID) // 必须排序
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToList();
bool allAdults = students.All(s => s.Birthday <= DateTime.Now.AddYears(-18));
bool anyAdults = students.Any(s => s.Birthday <= DateTime.Now.AddYears(-18));
bool containsWangWu = students.Contains(students.First(s => s.StudentName == "王五"));
LINQ提供了类似于SQL的查询语法,允许开发者以几乎相同的方式对不同类型的数据源进行查询。查询语法使用from、where、select、orderby等关键字。
var querySyntaxResult = from student in students
where student.ClassID == 101
orderby student.StudentName ascending
select student;
Console.WriteLine("查询语法结果:");
foreach (var student in querySyntaxResult)
{
Console.WriteLine($"{student.StudentName}, ClassID: {student.ClassID}");
}
查询关键字:
方法语法也称为扩展方法语法,使用点号“.”和一系列扩展方法来构建查询。
var methodSyntaxResult = students
.Where(student => student.ClassID == 101)
.OrderBy(student => student.StudentName)
.ToList();
Console.WriteLine("方法语法结果:");
foreach (var student in methodSyntaxResult)
{
Console.WriteLine($"{student.StudentName}, ClassID: {student.ClassID}");
}
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}");
}