基本 LINQ 查询操作 (C#)Basic LINQ Query Operations (C#)

本主题简要介绍了 LINQLINQ 查询表达式和一些在查询中执行的典型操作。This topic gives a brief introduction to LINQLINQ query expressions and some of the typical kinds of operations that you perform in a query. 下面各主题中提供了更具体的信息:More detailed information is in the following topics:

LINQ 查询表达式LINQ Query Expressions

标准查询运算符概述 (C#)Standard Query Operators Overview (C#)

演练:用 C# 编写查询Walkthrough: Writing Queries in C#


如果你已熟悉查询语言(如 SQL 或 XQuery),则可以跳过本主题的大部分内容。If you already are familiar with a query language such as SQL or XQuery, you can skip most of this topic. 请参阅下一节中的“from 子句”部分,了解 LINQLINQ 查询表达式中的子句顺序。Read about the "from clause" in the next section to learn about the order of clauses in LINQLINQ query expressions.

获取数据源Obtaining a Data Source

LINQLINQ 查询中,第一步是指定数据源。In a LINQLINQ query, the first step is to specify the data source. 和大多数编程语言相同,在使用 C# 时也必须先声明变量,然后才能使用它。In C# as in most programming languages a variable must be declared before it can be used. LINQLINQ 查询中,先使用 from 子句引入数据源 (customers) 和范围变量 (cust) 。In a LINQLINQ query, the from clause comes first in order to introduce the data source (customers) and the range variable (cust).

//queryAllCustomers is an IEnumerable<Customer>
var queryAllCustomers = from cust in customers
                        select cust;

范围变量就像 foreach 循环中的迭代变量,但查询表达式中不会真正发生迭代。The range variable is like the iteration variable in a foreach loop except that no actual iteration occurs in a query expression. 当执行查询时,范围变量将充当对 customers 中每个连续的元素的引用。When the query is executed, the range variable will serve as a reference to each successive element in customers. 由于编译器可以推断 cust 的类型,因此无需显式指定它。Because the compiler can infer the type of cust, you do not have to specify it explicitly. 可通过 let 子句引入其他范围变量。Additional range variables can be introduced by a let clause. 有关详细信息,请参阅 let 子句For more information, see let clause.


对于非泛型数据源(例如 ArrayList),必须显式键入范围变量。For non-generic data sources such as ArrayList, the range variable must be explicitly typed. 有关详细信息,请参阅如何:使用 LINQ 查询 ArrayList (C#)from 子句For more information, see How to: Query an ArrayList with LINQ (C#) and from clause.


或许,最常见的查询操作是以布尔表达式的形式应用筛选器。Probably the most common query operation is to apply a filter in the form of a Boolean expression. 筛选器使查询仅返回表达式为 true 的元素。The filter causes the query to return only those elements for which the expression is true. 将通过使用 where 子句生成结果。The result is produced by using the where clause. 筛选器实际指定要从源序列排除哪些元素。The filter in effect specifies which elements to exclude from the source sequence. 在下列示例中,仅返回地址位于“London”的 customersIn the following example, only those customers who have an address in London are returned.

var queryLondonCustomers = from cust in customers
                           where cust.City == "London"
                           select cust;

可使用熟悉的 C# 逻辑 ANDOR 运算符,在 where 子句中根据需要应用尽可能多的筛选器表达式。You can use the familiar C# logical AND and OR operators to apply as many filter expressions as necessary in the where clause. 例如,若要仅返回来自“London”的客户 AND 该客户名称为“Devon”,可编写以下代码:For example, to return only customers from "London" AND whose name is "Devon" you would write the following code:

where cust.City=="London" && cust.Name == "Devon"

要返回来自 London 或 Paris 的客户,可编写以下代码:To return customers from London or Paris, you would write the following code:

where cust.City == "London" || cust.City == "Paris"

有关详细信息,请参阅 where 子句For more information, see where clause.


对返回的数据进行排序通常很方便。Often it is convenient to sort the returned data. orderby 子句根据要排序类型的默认比较器,对返回序列中的元素排序。The orderby clause will cause the elements in the returned sequence to be sorted according to the default comparer for the type being sorted. 例如,基于 Name 属性,可将下列查询扩展为对结果排序。For example, the following query can be extended to sort the results based on the Name property. 由于 Name 是字符串,默认比较器将按字母顺序从 A 到 Z 进行排序。Because Name is a string, the default comparer performs an alphabetical sort from A to Z.

var queryLondonCustomers3 = 
    from cust in customers
    where cust.City == "London"
    orderby cust.Name ascending
    select cust;

要对结果进行从 Z 到 A 的逆序排序,请使用 orderby…descending 子句。To order the results in reverse order, from Z to A, use the orderby…descending clause.

有关详细信息,请参阅 orderby 子句For more information, see orderby clause.


group 子句用于对根据您指定的键所获得的结果进行分组。The group clause enables you to group your results based on a key that you specify. 例如,可指定按 City 对结果进行分组,使来自 London 或 Paris 的所有客户位于单独的组内。For example you could specify that the results should be grouped by the City so that all customers from London or Paris are in individual groups. 在这种情况下,cust.City 是键。In this case, cust.City is the key.

// queryCustomersByCity is an IEnumerable<IGrouping<string, Customer>>
  var queryCustomersByCity =
      from cust in customers
      group cust by cust.City;

  // customerGroup is an IGrouping<string, Customer>
  foreach (var customerGroup in queryCustomersByCity)
      foreach (Customer customer in customerGroup)
          Console.WriteLine("    {0}", customer.Name);

使用 group 子句结束查询时,结果将以列表的形式列出。When you end a query with a group clause, your results take the form of a list of lists. 列表中的每个元素都是具有 Key 成员的对象,列表中的元素根据该键被分组。Each element in the list is an object that has a Key member and a list of elements that are grouped under that key. 在循环访问生成组序列的查询时,必须使用嵌套 foreach 循环。When you iterate over a query that produces a sequence of groups, you must use a nested foreach loop. 外层循环循环访问每个组,内层循环循环访问每个组的成员。The outer loop iterates over each group, and the inner loop iterates over each group's members.

如果必须引用某个组操作的结果,可使用 into 关键字创建能被进一步查询的标识符。If you must refer to the results of a group operation, you can use the into keyword to create an identifier that can be queried further. 下列查询仅返回包含两个以上客户的组:The following query returns only those groups that contain more than two customers:

// custQuery is an IEnumerable<IGrouping<string, Customer>>
var custQuery =
    from cust in customers
    group cust by cust.City into custGroup
    where custGroup.Count() > 2
    orderby custGroup.Key
    select custGroup;

有关详细信息,请参阅 group 子句For more information, see group clause.


联接操作在不同序列间创建关联,这些序列在数据源中未被显式模块化。Join operations create associations between sequences that are not explicitly modeled in the data sources. 例如,可通过执行联接来查找所有位置相同的客户和分销商。For example you can perform a join to find all the customers and distributors who have the same location. LINQLINQ 中,join 子句始终作用于对象集合,而非直接作用于数据库表。In LINQLINQ the join clause always works against object collections instead of database tables directly.

var innerJoinQuery =
    from cust in customers
    join dist in distributors on cust.City equals dist.City
    select new { CustomerName = cust.Name, DistributorName = dist.Name };

LINQLINQ 中,不必像在 SQL 中那样频繁使用 join,因为 LINQLINQ 中的外键在对象模型中表示为包含项集合的属性。In LINQLINQ you do not have to use join as often as you do in SQL because foreign keys in LINQLINQ are represented in the object model as properties that hold a collection of items. 例如 Customer 对象包含 Order 对象的集合。For example, a Customer object contains a collection of Order objects. 不必执行联接,只需使用点表示法访问订单:Rather than performing a join, you access the orders by using dot notation:

from order in Customer.Orders...  

有关详细信息,请参阅 join 子句For more information, see join clause.

选择(投影)Selecting (Projections)

select 子句生成查询结果并指定每个返回的元素的“形状”或类型。The select clause produces the results of the query and specifies the "shape" or type of each returned element. 例如,可以指定结果包含的是整个 Customer 对象、仅一个成员、成员的子集,还是某个基于计算或新对象创建的完全不同的结果类型。For example, you can specify whether your results will consist of complete Customer objects, just one member, a subset of members, or some completely different result type based on a computation or new object creation. select 子句生成除源元素副本以外的内容时,该操作称为投影 。When the select clause produces something other than a copy of the source element, the operation is called a projection. 使用投影转换数据是 LINQLINQ 查询表达式的一种强大功能。The use of projections to transform data is a powerful capability of LINQLINQ query expressions. 有关详细信息,请参阅使用 LINQ (C#)select 子句进行数据转换。For more information, see Data Transformations with LINQ (C#) and select clause.

请参阅See also