前面提到,查询可以推迟到访问数据项时再执行。在迭代使用查询时,查询会执行。而使用转换操作符会立即执行查询,把查询结果放在数组、列表或字典中。
在下面的例子中,调用ToList()扩展方法,立即执行查询,得到的结果放在List<T>类中:
static void ToList()
{
List<Racer> racers = (from r in Formula1.GetChampions()
where r.Starts > 100
orderby r.Starts descending
select r).ToList();
foreach(var racer in racers)
{
System.Console.WriteLine($"{racer.ToString()} {racer:S}");
}
}
查询结果显示如下:
Graham Hill 176
Jack Brabham 125
Denny Hulme 112
John Surtees 111
把返回的对象放在列表中并没有这么简单。例如,对于集合类从赛车到赛车手的快速访问,可以使用新类Lookup<TKey,TElement>。
注:Dictionary<TKey,TValue>类只支持一个键对应一个值。在System.Linq名称空间的类Lookup<TKey,TElement>类中,一个键而可以对应多个值。
使用复合的from查询,可以摊平赛车手和赛车序列,创建带有Car和Racer属性的匿名类型。在返回的Lookup对象中,键的类型应是表示汽车的string,值的类型应是Racer。为了进行这个选择,可以给ToLookup()方法的一个重载版本传递一个键和一个元素选择器。键选择器引用Car属性,元素选择器引用Racer属性:
static void ToLookup()
{
var racers = (from r in Formula1.GetChampions()
from c in r.Cars
select new {
Car = c,
Racer = r
}).ToLookup(rc=>rc.Car,rc=>rc.Racer);
if(racers.Contains("Ferrari"))
{
foreach(var ferrariRacer in racers["Ferrari"])
{
System.Console.WriteLine(ferrariRacer.ToString());
}
}
}
用Lookup类的索引器访问的所有"Ferrari"冠军,结果如下:
Alberto Ascari
Juan Manuel Fangio
Mike Hawthorn
Phil Hill
John Surtees
如果需要在非类型化的集合上(如ArrayList)使用LINQ查询,就可以使用Cast()方法。在下面的例子中,基于Object类型的ArrayList集合用Race对象填充。为定义强类型化的查询,可使用Cast()方法:
static void ConvertWithCast()
{
var list = new ArrayList(Formula1.GetChampions() as ICollection);
var query = from r in list.Cast<Racer>()
where r.Country == "Italy"
orderby r.Wins descending
select r;
foreach(var racer in query)
{
System.Console.WriteLine($"{racer:A}");
}
}
结果仅包含来自意大利的一级方程式冠军:
Alberto,Ascari,Italy; starts:32, wins:10
Nino,Farina,Italy; starts:33, wins:5