下面介绍一些查询的示例,示例应用程序是一个控制台应用程序,使用了如下名称空间:
System
System.Collections.Generic
System.Linq
使用where子句,可以合并多个表达式。例如,找出赢得至少7场比赛的意大利和奥地利赛车手。传递给where子句的表达式的结果类型应是布尔类型:
static void Filtering()
{
var racers = from r in Formula1.GetChampions()
where r.Wins > 7&& (r.Country == "Italy"|| r.Country =="Austria")
select r;
foreach(var r in racers)
{
System.Console.WriteLine($"{r:A}");
}
}
用这个LINQ查询启动程序,返回的结果如下:
Alberto,Ascari,Italy; starts:32, wins:10
Jochen,Rindt,Austria; starts:60, wins:7
并不是所有的查询都可以用LINQ查询语法完成。也不是所有的扩展方法都映射到LINQ查询子句上。高级查询需要使用扩展方法。为了更好地理解带扩展方法的复杂查询。最好看看简单的查询是如何映射的。使用扩展方法Where()和Select(),会生成与前面LINQ查询非常类似的结果:
static void FilteringWithMethods()
{
var racers = Formula1.GetChampions()
.Where(r=>r.Wins >= 7 && (r.Country == "Italy" ||r.Country == "Austria"))
.Select(r=>r);
foreach(var r in racers)
{
System.Console.WriteLine($"{r:A}");
}
}
用索引筛选
不能使用LINQ查询的一个例子是Where()方法的重载。在Where()方法的重载中,可以传递第二个参数——索引。索引是筛选器返回的每个结果的计数器。可以在表达式中使用这个索引,执行基于索引的计算。下面的代码由Where()扩展方法调用,它使用索引返回姓氏以A开头、索引为非偶数的赛车手:
static void FilteringWithIndex()
{
var racers = Formula1.GetChampions()
.Where((r,index)=>r.LastName.StartsWith("A") && index%2 != 0)
;
foreach(var r in racers)
{
System.Console.WriteLine($"{r:A}");
}
}
结果如下:
Alberto,Ascari,Italy; starts:32, wins:10
类型筛选
为了进行基于类型的筛选,可以使用OfType()扩展方法。这里数组数据包含string和int对象。使用OfType()扩展方法,把string类传送给泛型参数,就从集合中仅返回字符串:
static void TypeFiltering(){
object[] data = {"one",2,3,"four","five",6};
var query = data.OfType<string>();
foreach(var s in query)
{
System.Console.WriteLine(s);
}
}
运行这段代码,就会显示字符串one、four和five。
one
four
five
复合的from子句
如果需要根据对象的一个成员进行筛选,而该成员本身是一个系列,就可以使用复合的from子句。Racer类定义了一个属性Cars,其中Cars是一个字符串数组。要筛选驾驶法拉利的所有冠军,可以使用如下所示的LINQ查询。第一个from子句访问从Formula.GetChanpions()方法返回的Racer对象,第二个from子句访问Racer类的Cars属性,以返回所有string类型的赛车手。接着在where子句中使用这些赛车筛选驾驶法拉第的所有冠军。
static void CompoundFrom()
{
var ferrariDrivers = from r in Formula1.GetChampions()
from c in r.Cars
where c == "Ferrari"
orderby r.LastName
select r.FirstName + " " + r.LastName;
foreach(var r in ferrariDrivers)
{
System.Console.WriteLine(r);
}
}
C#编辑器把复合的from子句和LINQ查询转换为SelectMany()扩展方法。SelectMany()方法可用于迭代序列的序列。示例中SelectMany()方法的重载版本如下所示:
public static IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(
this IEnumerable<TSource> sources,
Func<TSource,IEnumerable<TCollection>> collectionSelector,
Func<TSource,TCollection,TResult> resultSelector);
第一个参数是隐式参数,它从GetChampions()方法中接收Racer对象序列。第二个参数是collectionSelector委托,其中定义了内部序列。在lambda表达式 r=>r.Cars 中,应返回赛车集合。第三个参数是一个委托,现在为每个赛车调用该委托,接收Racer和Car对象。lambda表达式创建了一个匿名类型,它有Racer和Car属性。这个SelectMany()方法的结果示摊平了赛车手和赛车的层次结构,为每辆赛车返回匿名类型的一个新对象集合。
这个新集合传递给Where()方法,筛选出驾驶法拉利的赛车手。最后,调用OrderBy()和Select()方法:
static void CompundFromWithMethod()
{
var ferrariDrivers = Formula1.GetChampions()
.SelectMany(r=>r.Cars,(r,c)=> new {Racer = r,Car= c})
.Where(r=>r.Car == "Ferrari")
.OrderBy(r=>r.Racer.LastName)
.Select(r=>r.Racer.FirstName + " " + r.Racer.LastName);
foreach(var r in ferrariDrivers)
{
System.Console.WriteLine(r);
}
}
把SelectMany()泛型方法解析为这里使用的类型,所解析的类型如下所示。在这个例子中,数据源是Racer类型,所筛选的集合是一个string数组,当然所返回的匿名类型的名称是未知的,这里显示为TResult:
public static IEnumerable<TResult> SelectMany<Racer,string,TResult>(
this IEnumerable<Racer> sources,
Func<Racer,IEnumerable<string>> collectionSelector,
Func<Racer,string,TResult> resultSelector);
因为查询仅从LINQ查询转换为扩展方法,所以结果与前面的相同。
本文通过示例介绍了如何使用C#中的LINQ进行数据筛选,包括:使用where子句进行条件筛选,结合索引进行更复杂的过滤,利用OfType()进行类型筛选,以及运用复合的from子句和SelectMany()方法对对象成员内的序列进行筛选。通过这些方法,可以实现对数据的深度查询和处理。
362

被折叠的 条评论
为什么被折叠?



