练习1 –面向内存中集合的LINQ
在本练习中,您将学习如何查询对象序列。所有支持System.Collections.Generic.IEnumerable接口或范型接口IEnumerable<T>的集合都被认为是一个序列,并且可以使用新的LINQ标准查询运算符进行操作。标准查询运算符允许程序员来构建查询,包括在进行投影时创建新的类型。这与类型接口的功能是紧密相关的,它允许变量由它的初始化表达式来标定类型。
任务1 –创建 “LINQ Overview” 解决方案
点击Start | Programs | Microsoft Visual Studio 2008| Microsoft Visual Studio 2008菜单项,打开Visual Studio 2008。
点击File | New | Project… 菜单命令。
在 New Project 对话框中,选择Visual C# Windows 项目类型。
选择Console Application 项目模板。
为新建的项目指定名称,在Name框中输入“LINQ Overview”。
点击OK。
任务 2 – 查询一个整数类型的列表
在 Solution Explorer中,双击Program.cs
创建一个新的方法,声明一个整数类型的集合(将该方法放到Program类中):
{
static void Main(string[] args)
{
}
static void NumQuery()
{
var numbers = new int[] { 1, 4, 9, 16, 25, 36 };
}
}
注意,赋值式子左边并没有使用一个显式的类型声明;而是使用了一个新的关键字var。这是C# 3.0里面的一个新的功能,隐匿的本地类型声明。这个功能允许本地变量由编译器来推断出它的类型。在这里,右边创建了一个Int32[]类型的对象,因此编译器将推断出它的类型是Int32[]。这样也使得一些变量在初始化的时候才得到它的类型名称。
添加下面的代码,来查询集合中的所有偶数。
{
var numbers = new int[] { 1, 4, 9, 16, 25, 36 };
var evenNumbers = from p in numbers
where (p % 2) == 0
select p;
}
在这个步骤中,赋值式子右边的是一个查询表达式,是LINQ项目所引入的另一个语言扩展。和上面的步骤中的一样,使用类型推断来简化代码。查询返回的类型可能并不是非常明显。这个示例将返回System.Collections.Generic.IEnumerable<Int32>类型;将鼠标移动到evenNumbers上可以在Quick Info中看到类型。确实,有时候没有办法指定类型,这样就需要指定匿名的类型(由对象的初始化代码自动推断和创建的类型)。类型推断为这个问题提供了一种简单的解决方案。
添加下面的代码以显示结果:
{
var numbers = new int[] { 1, 4, 9, 16, 25, 36 };
var evenNumbers = from p in numbers
where (p % 2) == 0
select p;
Console.WriteLine("Result:");
foreach (var val in evenNumbers)
Console.WriteLine(val);
}
注意,foreach 语句已经被扩展到可以使用类型推断了。
最后,向Main函数中添加对NumQuery方法的调用:
{
NumQuery();
}
点击Ctrl+F5 来构建和运行应用程序。这时将会出现一个控制台。正如预期的那样,所有的偶数将会被显示出来(包括数字4、16、和36 将会出现在控制台的输出中)。
点击任意键,以结束应用程序。
任务 3 – 查询结构化类型
在本任务中,您将不再使用基本类型,而是要将查询功能应用到自定义的结构类型当中。在Program类的声明上面,添加下面的代码以创建一个Customer类:
{
public string CustomerID { get; set; }
public string City { get; set; }
public override string ToString()
{
return CustomerID + "\t" + City;
}
}
class Program
…
注意,这里使用到了C#语言的另外一个功能,自实现(auto-implemented)属性。在上面的代码中,使用这种功能创建了两个属性,它们将会自动包含后端的字段。另外,要注意的是,没有声明构造函数。在早期的C#版本中,如果这样去构造类的话,就需要类的调用者使用默认的无参数构造函数创建一个对象实例,然后再使用单独的语句分别设置它的字段与属性值。
Within the Program class declaration, create the following new method, which creates a list of customers (taken from the Northwind database):
在Program类的声明中,创建下面的方法,它将创建一个客户列表(该数据是从Northwind数据库中获取出来的):
{
NumQuery();
}
static IEnumerable<Customer> CreateCustomers()
{
return new List<Customer>
{
new Customer { CustomerID = "ALFKI", City = "Berlin" },
new Customer { CustomerID = "BONAP", City = "Marseille" },
new Customer { CustomerID = "CONSH", City = "London" },
new Customer { CustomerID = "EASTC", City = "London" },
new Customer { CustomerID = "FRANS", City = "Torino" },
new Customer { CustomerID = "LONEP", City = "Portland" },
new Customer { CustomerID = "NORTS", City = "London" },
new Customer { CustomerID = "THEBI", City = "Portland" }
};
}
在上面的代码段中,还有一些非常有趣的地方值得注意一下。首先,注意到新建集合时直接使用大括号来创建的。也就是说,即便它的类型是List<T>,而不是数组,也可以使用大括号来进行声明并添加元素,不用再像以前一些使用Add方法。另外,注意到Customer元素也是使用一种新的语法来创建的(叫做对象初始化器(object initializer)。即使Customer类没有包含两个参数的构造函数,也可以像表达式一样,通过在大括号中显式的设定它的属性,来创建这个类的对象。
接下来,查询集合以找到居住在伦敦的所有客户。添加下面的查询方法ObjectQuery,并在Main方法中添加对它的调用(删除对StringQuery的调用)。
{
var results = from c in CreateCustomers()
where c.City == "London"
select c;
foreach (var c in results)
Console.WriteLine(c);
}
static void Main(string[] args)
{
ObjectQuery();
}
需要再次注意的是,编译器使用类型推断来强类型化foreach循环中的results变量。
点击Ctrl+F5 以构建并运行应用程序。查看完结果后,点击任意键以结束应用程序。
将会显示出三个结果。正如您所看到的那样,当使用LINQ查询表达式时,处理复杂的类型的过程与处理基本类型的过程是一样。