C# LINQ 用法详解
一、LINQ 概念
语言集成查询(LINQ)
LINQ 是一种统一的查询语法,它允许使用类似 SQL 的语法来查询各种数据源,如集合、数据库、XML 等。它将查询能力直接集成到 C# 语言中。
LINQ 提供程序
是实现 LINQ 语法与特定数据源之间转换的组件。例如,LINQ to Objects 用于查询内存中的集合对象;LINQ to SQL 用于查询 SQL Server 数据库;LINQ to XML 用于查询 XML 数据。
数据源
是 LINQ 查询操作的对象,可以是数组、列表、数据库表、XML 文档等。它提供了数据供查询使用。
查询表达式
是使用 LINQ 语法编写的代码片段,用于从数据源中检索数据。它通常以 from、where、select 等关键字开头,以 select 或 group 关键字结尾。
延迟执行(Deferred Execution)
LINQ 查询的执行被延迟到实际获取查询结果时才进行。这意味着查询的定义和执行是分离的,只有在需要实际结果时(如通过 foreach 遍历结果或使用 ToList() 等方法)才会执行查询。
立即执行(Immediate Execution)
与延迟执行相对,有些 LINQ 操作符(如 ToList()、ToArray()、Count() 等)会立即执行查询并返回结果。
二、LINQ 类别及用法
LINQ to Objects
概念 :用于查询内存中的集合对象,如数组、列表等。
示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqToObjectsExample
{
class Program
{
static void Main(string[] args)
{
// 创建一个整数列表
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 查询大于 5 的数字
var result = from num in numbers
where num > 5
select num;
// 遍历查询结果
foreach (var item in result)
{
Console.WriteLine(item);
}
// 立即执行查询并转换为列表
List<int> resultList = numbers.Where(n => n > 5).ToList();
foreach (int item in resultList)
{
Console.WriteLine(item);
}
}
}
}
LINQ to SQL
概念 :用于查询 SQL Server 数据库。它提供了一种对象关系映射(O/RM)的方式,将数据库表映射为 C# 类。
示例代码(需要添加 System.Data.Linq 引用)
using System;
using System.Linq;
namespace LinqToSqlExample
{
class Program
{
static void Main(string[] args)
{
// 创建数据库连接上下文
using (var db = newDataContext("Your_Connection_String"))
{
// 查询所有 Product 表中的产品,价格大于 100
var products = from p in db.Products
where p.Price > 100
select p;
foreach (var product in products)
{
Console.WriteLine($"{product.Name}: {product.Price}");
}
}
}
}
// 数据库上下文类
public class DataContext : System.Data.Linq.DataContext
{
public DataContext(string connection) : base(connection) { }
public System.Data.Linq.Table<Product> Products;
}
// 产品类(映射数据库表)
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
LINQ to XML
概念 :用于查询和操作 XML 数据。它提供了一组丰富的 API 来创建、修改、查询 XML 文档。
示例代码
using System;
using System.Linq;
using System.Xml.Linq;
namespace LinqToXmlExample
{
class Program
{
static void Main(string[] args)
{
// 创建 XML 文档
XElement xml = new XElement("Students",
new XElement("Student",
new XElement("Name", "John"),
new XElement("Age", 20)),
new XElement("Student",
new XElement("Name", "Jane"),
new XElement("Age", 22))
);
// 查询年龄大于 20 的学生
var students = from student in xml.Elements("Student")
let age = int.Parse(student.Element("Age").Value)
where age > 20
select student.Element("Name").Value;
foreach (var student in students)
{
Console.WriteLine(student);
}
}
}
}
不过上面代码中的查询语句也可以改为lambda 表达式风格来写,例如:
var students = xml.Elements("Student")
.Where(s => int.Parse(s.Element("Age").Value) > 20)
.Select(s => s.Element("Name").Value);
效果是一样的。
LINQ 标准查询操作符
- 过滤操作符
- Where :用于根据条件过滤元素。
- 示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace WhereExample
{
class Program
{
static void Main(string[] args)
{
List<string> fruits = new List<string> { "Apple", "Banana", "Cherry", "Date" };
// 查询以 'A' 开头的水果
var fruitsWithA = fruits.Where(fruit => fruit.StartsWith("A"));
foreach (var fruit in fruitsWithA)
{
Console.WriteLine(fruit);
}
}
}
}
- 选择操作符
- Select :用于投影元素,将每个元素转换为新的形式。
- 示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace SelectExample
{
class Program
{
static void Main(string[] args)
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
// 将数字投影为它们的平方
var squares = numbers.Select(num => num * num);
foreach (var square in squares)
{
Console.WriteLine(square);
}
}
}
}
- 排序操作符
- OrderBy :用于按升序排序元素。
- OrderByDescending :用于按降序排序元素。
- ThenBy :用于在主要排序的基础上进行次要排序。
- ThenByDescending :用于在主要排序的基础上进行次要降序排序。
- 示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace OrderByExample
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>
{
new Student{ Name = "John", Age = 20 },
new Student{ Name = "Jane", Age = 22 },
new Student{ Name = "Bob", Age = 19 }
};
// 按年龄升序排序学生
var sortedStudents = students.OrderBy(student => student.Age);
foreach (var student in sortedStudents)
{
Console.WriteLine($"{student.Name}: {student.Age}");
}
// 按年龄降序排序学生
var sortedStudentsDescending = students.OrderByDescending(student => student.Age);
foreach (var student in sortedStudentsDescending)
{
Console.WriteLine($"{student.Name}: {student.Age}");
}
// 按年龄升序排序,然后按姓名降序排序
var sortedStudentsThenBy = students.OrderBy(student => student.Age).ThenByDescending(student => student.Name);
foreach (var student in sortedStudentsThenBy)
{
Console.WriteLine($"{student.Name}: {student.Age}");
}
}
}
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
}
- 聚合操作符
- Count :用于计算集合中的元素个数。
- Sum :用于计算集合中元素的总和。
- Average :用于计算集合中元素的平均值。
- Max :用于获取集合中的最大值。
- Min :用于获取集合中的最小值。
- 示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace AggregateExample
{
class Program
{
static void Main(string[] args)
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 计算元素个数
int count = numbers.Count();
Console.WriteLine($"Count: {count}");
// 计算总和
int sum = numbers.Sum();
Console.WriteLine($"Sum: {sum}");
// 计算平均值
double average = numbers.Average();
Console.WriteLine($"Average: {average}");
// 获取最大值
int max = numbers.Max();
Console.WriteLine($"Max: {max}");
// 获取最小值
int min = numbers.Min();
Console.WriteLine($"Min: {min}");
}
}
}
- 分组操作符
- GroupBy :用于根据指定的键将元素分组。
- 示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace GroupByExample
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>
{
new Student{ Name = "John", Grade = "A" },
new Student{ Name = "Jane", Grade = "B" },
new Student{ Name = "Bob", Grade = "A" }
};
// 按成绩分组学生
var groupedStudents = students.GroupBy(student => student.Grade);
foreach (var group in groupedStudents)
{
Console.WriteLine($"Grade: {group.Key}");
foreach (var student in group)
{
Console.WriteLine(student.Name);
}
}
}
}
public class Student
{
public string Name { get; set; }
public string Grade { get; set; }
}
}
- 连接操作符
- Join :用于将两个集合中的元素基于键进行连接。
- 示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace JoinExample
{
class Program
{
static void Main(string[] args)
{
List<Student> students = new List<Student>
{
new Student{ Id = 1, Name = "John" },
new Student{ Id = 2, Name = "Jane" }
};
List<Course> courses = new List<Course>
{
new Course{ StudentId = 1, CourseName = "Math" },
new Course{ StudentId = 2, CourseName = "Science" }
};
// 将学生和课程进行连接
var studentCourses = from student in students
join course in courses on student.Id equals course.StudentId
select new { student.Name, course.CourseName };
foreach (var item in studentCourses)
{
Console.WriteLine($"{item.Name}: {item.CourseName}");
}
}
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Course
{
public int StudentId { get; set; }
public string CourseName { get; set; }
}
}
- 集合操作符
- Union :用于合并两个集合,并返回去重后的结果。
- Intersect :用于获取两个集合的交集。
- Except :用于获取两个集合的差集。
- Concat :用于合并两个集合(不去重)。
- 示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace SetExample
{
class Program
{
static void Main(string[] args)
{
List<int> list1 = new List<int> { 1, 2, 3, 4 };
List<int> list2 = new List<int> { 3, 4, 5, 6 };
// 合并两个集合并去重
var union = list1.Union(list2);
Console.WriteLine("Union:");
foreach (var item in union)
{
Console.WriteLine(item);
}
// 获取交集
var intersect = list1.Intersect(list2);
Console.WriteLine("\nIntersect:");
foreach (var item in intersect)
{
Console.WriteLine(item);
}
// 获取差集(list1 中有而 list2 中没有的元素)
var except = list1.Except(list2);
Console.WriteLine("\nExcept:");
foreach (var item in except)
{
Console.WriteLine(item);
}
// 合并两个集合(不去重)
var concat = list1.Concat(list2);
Console.WriteLine("\nConcat:");
foreach (var item in concat)
{
Console.WriteLine(item);
}
}
}
}
- 转换操作符
- OfType :用于过滤并转换集合中的元素类型。
- Cast :用于将集合中的元素强制转换为指定类型。
- ToList :用于将集合转换为列表。
- ToArray :用于将集合转换为数组。
- ToDictionary :用于将集合转换为字典。
- 示例代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace ConvertExample
{
class Program
{
static void Main(string[] args)
{
ArrayList mixedList = new ArrayList { 1, "John", 2, "Jane", 3 };
// 筛选整数并转换为列表
List<int> intList = mixedList.OfType<int>().ToList();
foreach (var item in intList)
{
Console.WriteLine(item);
}
// 将集合转换为字典
var dict = mixedList.OfType<int>().ToDictionary(x => x, x => x * 2);
foreach (var keyValuePair in dict)
{
Console.WriteLine($"{keyValuePair.Key}: {keyValuePair.Value}");
}
}
}
}
- 元素操作符
- First :用于获取集合中的第一个元素。
- FirstOrDefault :用于获取集合中的第一个元素,如果集合为空,则返回默认值。
- Last :用于获取集合中的最后一个元素。
- LastOrDefault :用于获取集合中的最后一个元素,如果集合为空,则返回默认值。
- Single :用于获取集合中唯一的元素,如果集合中没有元素或有多个元素则抛出异常。
- SingleOrDefault :用于获取集合中唯一的元素,如果集合为空则返回默认值,如果有多个元素则抛出异常。
- ElementAt :用于获取集合中指定索引的元素。
- ElementAtOrDefault :用于获取集合中指定索引的元素,如果索引超出范围则返回默认值。
- 示例代码
using System;
using System.Collections.Generic;
using System.Linq;
namespace ElementExample
{
class Program
{
static void Main(string[] args)
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
// 获取第一个元素
int first = numbers.First();
Console.WriteLine($"First: {first}");
// 获取最后一个元素
int last = numbers.Last();
Console.WriteLine($"Last: {last}");
// 获取唯一元素(如果有多个元素会抛异常)
List<int> singleList = new List<int> { 1 };
int single = singleList.Single();
Console.WriteLine($"Single: {single}");
// 获取指定索引的元素
int elementAt = numbers.ElementAt(2);
Console.WriteLine($"ElementAt: {elementAt}");
}
}
}
- 生成操作符
- DefaultIfEmpty :用于如果集合为空,则返回一个包含默认值的集合。
- Empty :用于创建一个空的集合。
- Range :用于生成一个数字序列。
- Repeat :用于生成一个包含重复元素的集合。
- 示例代码
using System;
using System.Linq;
namespace GenerateExample
{
class Program
{
static void Main(string[] args)
{
List<int> emptyList = new List<int>();
// 如果集合为空,返回包含默认值的集合
var defaultIfEmpty = emptyList.DefaultIfEmpty(0);
Console.WriteLine("DefaultIfEmpty:");
foreach (var item in defaultIfEmpty)
{
Console.WriteLine(item);
}
// 生成一个数字序列
var range = Enumerable.Range(1, 5);
Console.WriteLine("\nRange:");
foreach (var item in range)
{
Console.WriteLine(item);
}
// 生成一个包含重复元素的集合
var repeat = Enumerable.Repeat("Hello", 3);
Console.WriteLine("\nRepeat:");
foreach (var item in repeat)
{
Console.WriteLine(item);
}
}
}
} 
发表评论