有了这些预备知识和实体类,我们就可以使用Linq进行查询了。
1、简单的筛选
使用Where子句可以对数据源进行简单的筛选。下变例子是找出至少赢得15场比赛的奥地利车手:
/// <summary>
/// 1、最简单的查询
/// </summary>
static void LinqQuery1()
{
var query = from r in Formula1.GetChampions()
where (r.Country == "Brazil" || r.Country == "Austria") && r.Wins > 15
orderby r.Wins descending
select r;
foreach (var racer in query)
{
Console.WriteLine("{0:A}", racer);
}
}
这段代码的功能可以使用System.Linq中的扩展方法来实现:
【代码】
var query2 = Formula1.GetChampions()
.Where(r => r.Country == "Brazil" || r.Country == "Austria")
.Select(r=>r);
注:并不是所有的查询都可以使用Linq查询或者扩展方法都可以实现的。高级查询需要使用扩展方法。
2、用索引进行筛选
Where()扩展方法的一个重载中,可以对该方法传递第二个参数:索引。索引是筛选器返回的每个结果的计数器,可以在表达式中使用索引,执行一些索引相关的计算。现编的代码使用Where()扩展方法,返回姓氏以A开头,索引为偶数的车手:
/// <summary>
/// 2、使用索引i进行选
/// </summary>
static void LinqQuery2()
{
//使用索引i进行筛选
var query = Formula1.GetChampions()
.Where((r, i) => r.LastName.StartsWith("A") && i % 2 != 0);
foreach (var item in query)
{
Console.WriteLine("{0:A}", item);
}
}
3、筛选出不同的数据类型
使用OfType()扩展方法,可以实现基于类型的筛选。下面的代码中定义了包含了string和int类型的对象,使用OfType()方法从集合中找出字符串:
/// <summary>
/// 3、类型筛选
/// </summary>
static void LinqQuery3()
{
object[] data = { "one", 1, 2, 3, "two", "three" };
var query = data.OfType<string>();
foreach (var item in query)
{
Console.WriteLine(item);
}
}
4、复合的from子句
复合的from子句用于对这样一种情况的查询:需要根据对象的一个成员进行筛选,而这个成员本身是一组数据。
本例中,Racer类定义的属性Cars就是这样的一个属性。Cars是一个字符串数组。
使用如下的Linq查询可以筛选出嘉实法拉利的所有冠军:
var query = from r in Formula1.GetChampions()
from c in r.Cars
where c == "Ferrari"
orderby r.LastName
select r;
其中,第一个from子句用于访问从Formyla1.GetChampions方法返回的Racer对象,第二个from子句访问Racer类的Cars属性,返回所有string类型的赛车,最后使用Where子句从这些赛车中筛选出所有冠军。
这里C#编译器将符合的from子句和Linq查询转换成SelectMany()方法,SelectMany()方法可以用于迭代序列的序列。使用SelectMany()扩展方法的代码如下:
var query = Formula1.GetChampions()
.SelectMany(r => r.Cars, (r, c) => new { Racer = r, Car = c })
.Where(r => r.Car == "Ferrari")
.OrderBy(r => r.Racer.FirstName)
.Select(r => r.Racer.FirstName + " " + r.Racer.LastName);
这里SelectMany()方法的第一个参数是隐式参数,他从GetChampions方法中接收Racer对象序列,第二个参数是collectionSelector委托,其中定义了内部序列。在Lambda表达式r=>r.Cars中,返回赛车集合。第三个参数是一个Func<T>委托,这里为每个Car调用该委托接收Racer和Cars对象。Lambda表达式创建了一个包含了Racer和Cars属性的匿名的类型。这个SelectMany方法的结果摊平了赛手和赛车的层次结构,为每个赛车返回匿名类型的一个新对象耦合。
这段解释有点拗口,因为Lambda表达式确实比较难以解释,还有使用了几个Func<T>委托,不了解委托看这段代码简直就是天书。不过VS的职能提示挺管用的,在敲出几个代码之后看看他的提示在继续写也是不错的。
5、对筛选结果进行排序
使用orderby和orderby descending子句或者OrderBy()和OrderByDescending()扩展方法可以实现对筛选结果的排序。
下面这段代码是对筛选出来的赛手使用赢得比赛的次数进行排序:
//简单的Linq语句查询排序
var query1 = from r in Formula1.GetChampions()
where r.Country == "Brazil"
orderby r.Wins descending
select r;
转换成扩展方法后的实现:
//使用扩展方法
var query2 = Formula1.GetChampions()
.Where(r => r.Country == "Brazil")
.OrderByDescending(r => r.Wins)
.ThenByDescending(r=>r.LastName)
.Select(r => r);
最后还可以使用Take方法对结果进一步筛选:
//使用Take子句提取前十项数据
var query3 = (from r in Formula1.GetChampions()
orderby r.Country, r.LastName, r.FirstName
select r)
.Take(10);
//使用扩展方法查询
var query = Formula1.GetChampions()
.OrderBy(r => r.Country)
.ThenBy(r => r.LastName)
.ThenBy(r => r.FirstName)
.Take(10)
.Select(r => r);