LINQ (Language Integrated Query) 是 C# (以及 VB.NET) 中的一组技术,它将查询功能直接集成到 C# 语言中,提供了一种统一的、类型安全的方式来查询和操作来自各种数据源的数据。
简单来说,LINQ 语句允许你使用类似于 SQL 的语法来查询内存中的对象集合 (如 List<T>
, Array
)、XML 文档、数据库 (通过 LINQ to SQL, Entity Framework 等)、ADO.NET 数据集等。
核心思想
- 语言集成 (Language Integrated): 查询不再是作为字符串传递给数据库或其他系统的命令,而是 C# 语言本身的一部分。这意味着你可以获得编译时类型检查、IntelliSense 支持和调试器支持。
- 统一的查询模型 (Unified Query Model): 无论数据源是什么(对象、XML、数据库),查询的基本语法和模式都是相似的。这减少了学习不同数据访问 API 的复杂性。
- 强类型 (Strongly Typed): 查询的结果通常也是强类型的对象,这有助于在编译时捕获错误,而不是在运行时。
主要语法形式
-
查询语法 (Query Syntax / Declarative Syntax):
- 这种语法非常类似于 SQL,对于熟悉 SQL 的开发者来说更容易理解和上手。
- 它使用
from
,where
,select
,orderby
,join
,group by
等关键字。 - 更具可读性,尤其对于复杂的查询。
示例 (查询语法):
// 假设有一个名为 numbers 的整数列表 List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // 查询所有大于 5 的偶数,并按降序排列 var evenNumbersGreaterThanFive = from num in numbers where num > 5 && num % 2 == 0 orderby num descending select num; foreach (var n in evenNumbersGreaterThanFive) { Console.WriteLine(n); // 输出: 10, 8, 6 }
-
方法语法 (Method Syntax / Fluent Syntax):
- 这种语法使用一系列的扩展方法 (Extension Methods),这些方法通常定义在
System.Linq.Enumerable
或System.Linq.Queryable
类中。 - 每个方法通常对应查询语法中的一个子句(例如
Where()
,Select()
,OrderBy()
)。 - 方法语法可以链式调用,对于简单的查询可能更简洁,并且有些 LINQ 操作符只能通过方法语法使用。
- Lambda 表达式通常与方法语法一起使用来定义查询的逻辑。
示例 (方法语法):
// 假设有一个名为 numbers 的整数列表 List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // 查询所有大于 5 的偶数,并按降序排列 var evenNumbersGreaterThanFive = numbers .Where(num => num > 5 && num % 2 == 0) .OrderByDescending(num => num) .Select(num => num); // 在这个简单例子中,Select(num => num) 可以省略 foreach (var n in evenNumbersGreaterThanFive) { Console.WriteLine(n); // 输出: 10, 8, 6 }
- 这种语法使用一系列的扩展方法 (Extension Methods),这些方法通常定义在
关键组成部分
- from 子句: 指定数据源以及范围变量 (range variable)。每个 LINQ 查询都以
from
子句开始(或者join
子句引入新的数据源)。from item in collection
- where 子句 (可选): 用于根据条件筛选数据源中的元素。
where item.Property > value
- select 子句: 指定查询结果中每个元素的形状或类型。它可以返回原始元素、元素的一部分,或者基于原始元素创建新的对象。
select item
(返回整个元素)select item.Property
(返回元素的某个属性)select new { Name = item.Name, Age = item.Age }
(返回匿名类型)
- orderby 子句 (可选): 用于对查询结果进行排序(升序
ascending
(默认) 或降序descending
)。orderby item.Property ascending
- join 子句 (可选): 用于根据键将来自不同数据源的元素关联起来。
join otherItem in otherCollection on item.Key equals otherItem.Key
- group by 子句 (可选): 用于根据指定的键对元素进行分组。
group item by item.Category
- into 关键字: 可以用于在
join
或group by
子句之后创建一个临时的标识符,或者用于在查询末尾继续查询 (查询延续)。
不同提供程序 (Providers)
LINQ 的强大之处在于它可以应用于多种数据源,这是通过不同的 LINQ 提供程序实现的:
- LINQ to Objects: 用于查询内存中的
IEnumerable
或IEnumerable<T>
集合 (如数组、列表)。 - LINQ to XML (XLINQ): 用于查询和操作 XML 文档。
- LINQ to SQL (已基本被 Entity Framework 取代): 用于查询 Microsoft SQL Server 数据库。它将 LINQ 查询转换为 SQL 语句。
- LINQ to Entities (Entity Framework): Entity Framework (EF) 的一部分,是微软推荐的 ORM (Object-Relational Mapper),允许你使用 LINQ 查询多种数据库 (SQL Server, MySQL, PostgreSQL 等)。EF Core 是其现代、跨平台的版本。
- LINQ to DataSets: 用于查询 ADO.NET
DataSet
对象。 - 第三方 LINQ 提供程序: 许多其他数据源(如 NoSQL 数据库、Web 服务)也有自己的 LINQ 提供程序。
优点
- 可读性和可维护性: LINQ 查询通常比传统的循环和条件语句更容易阅读和理解,尤其对于复杂的数据操作。
- 编译时检查: 由于查询是语言的一部分,编译器可以在编译时捕获语法错误和类型不匹配,减少运行时错误。
- IntelliSense 支持: Visual Studio 等 IDE 为 LINQ 查询提供强大的 IntelliSense 支持,包括自动完成和参数信息。
- 减少代码量: 对于许多常见的数据操作,LINQ 可以用更少的代码实现相同的功能。
- 延迟执行 (Deferred Execution): 许多 LINQ 查询(尤其是返回
IEnumerable<T>
的查询)并不会立即执行,而是在枚举结果时(例如在foreach
循环中或调用ToList()
,ToArray()
等方法时)才执行。这可以提高性能,尤其是在处理大型数据集或构建动态查询时。某些操作符如Count()
,First()
会立即执行。
总而言之,LINQ 语句是 C# 中一种强大且富有表现力的方式,用于以声明式、类型安全的方式查询和转换数据,无论数据源是什么。它是现代 C# 开发中不可或缺的一部分。