若要有效地编写查询,应了解完整查询作中变量的类型如何相互关联。 如果你了解这些关系,你将更容易理解文档中的 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
,要意识到这可能会使你的代码更难让他人阅读。 有关详细信息,请参阅 隐式类型局部变量。