若要有效地编写查询,应了解完整查询作中变量的类型如何相互关联。 如果你了解这些关系,你将更容易理解文档中的 LINQ 示例和代码示例。 此外,你将了解在使用 var隐式类型化变量时会发生什么情况。
LINQ 查询操作在数据源、查询本身及查询执行中是强类型的。 查询中的变量类型必须与数据源中的元素的类型以及语句中的 foreach 迭代变量的类型兼容。 此强类型保证在编译时捕获类型错误,以便可以在用户遇到这些错误之前更正它们。
为了演示这些类型关系,后面的大多数示例都对所有变量使用显式键入。 最后一个示例演示在利用使用 var 的隐式类型时,如何应用相同的原则。
不对源数据进行转换的查询
下图显示了对数据不执行任何转换的 LINQ to Objects 查询作。 源包含字符串序列,查询输出也是字符串序列。

- 数据源的类型参数确定范围变量的类型。
- 所选对象的类型确定查询变量的类型。 下面是
name一个字符串。 因此,查询变量是一个IEnumerable<string>。 - 在
foreach语句中迭代查询变量。 由于查询变量是字符串序列,因此迭代变量也是字符串。
改变源数据的查询
下图显示了一个 LINQ to SQL 查询操作,该操作对数据进行简单转换。 查询采用一系列 Customer 对象作为输入,结果中仅选择 Name 属性。 由于 Name 是字符串,因此查询将生成一系列字符串作为输出。

- 数据源的类型参数确定范围变量的类型。
- 该
select语句返回Name属性而不是完整的Customer对象。 因为Name是字符串,类型参数是custNameQuery而不是string。 - 由于
custNameQuery是字符串序列,因此foreach循环的迭代变量也必须是一个string。
下图显示了稍微复杂一些的转换。 该 select 语句返回一个匿名类型,该类型只捕获原始 Customer 对象的两个成员。

- 数据源的类型参数始终是查询中范围变量的类型。
- 因为
select语句生成匿名类型,所以必须使用var隐式类型化查询变量。 - 由于查询变量的类型是隐式的,因此循环中的
foreach迭代变量也必须是隐式的。
让编译器推断类型信息
尽管你应该了解查询作中的类型关系,但可以选择让编译器为你完成所有工作。 关键字 var 可用于查询作中的任何局部变量。 下图类似于前面讨论的示例 2。 但是,编译器为查询作中的每个变量提供强类型。

LINQ 和泛型类型 (C#)
LINQ 查询基于泛型类型。 在开始编写查询之前,无需深入了解泛型。 但是,你可能想要了解两个基本概念:
- 创建泛型集合类 List<T>的实例时,请将“T”替换为列表将保留的对象类型。 例如,字符串列表表示为
List<string>,对象列表Customer表示为List<Customer>。 泛型列表是强类型化的,它比存储其元素为 Object 类型的集合具有更多优点。 如果尝试将Customer添加到List<string>,将在编译时收到错误。 使用泛型集合很容易,因为无需执行运行时类型强制转换。 - IEnumerable<T> 是允许使用语句枚举泛型集合类的
foreach接口。 泛型集合类支持 IEnumerable<T>,就像非泛型集合类(例如 ArrayList)支持 IEnumerable一样。
有关泛型的详细信息,请参阅 泛型。
LINQ 查询中的 IEnumerable<T> 变量
LINQ 查询变量被定义为 IEnumerable<T> 类型或某种派生类型,例如 IQueryable<T>。 当看到类型化为 IEnumerable<Customer>查询变量时,它只是意味着执行查询时,将生成零个或多个 Customer 对象的序列。
IEnumerable<Customer> customerQuery = from cust in customers
where cust.City == "London"
select cust;
foreach (Customer customer in customerQuery)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
让编译器处理泛型类型声明
如果愿意,可以使用 var 关键字来避免泛型语法。 关键字 var 指示编译器通过查看子句中指定的 from 数据源来推断查询变量的类型。 以下示例生成与上一示例相同的已编译代码:
var customerQuery2 = from cust in customers
where cust.City == "London"
select cust;
foreach(var customer in customerQuery2)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
当变量的类型明显或显式指定嵌套泛型类型(例如组查询生成的类型)并不重要时,关键字 var 非常有用。 一般来说,我们建议如果你使用var,要意识到这可能会使你的代码更难让他人阅读。 有关详细信息,请参阅 隐式类型局部变量。