金沙澳门官网7817网址LINQ(隐式表明式、lambda 表达式)

然后我们需要准备数据,武林高手类,本文使用的Linq查询包含了两种方式,另一种是使用System.Linq中定义的扩展方法进行的查询,语言执行查询,语言集成查询,在LINQ,的主要任务是负责过滤集合中的数据

金沙澳门官网7817网址 6

凑巧学习了 Siki先生 的C#教程Linq部分,以下是笔记

       
Linq是言语集成查询的简称。Linq简化了语言查询,是的技术员能够应用同样的语法查询差别的数据源。

       .NET 中一项突破性的更新是 LINQ(Language Integrated
Query,语言集成查询
),那组语言扩充让您可见不必离开舒适的 C#
语言奉行查询。

[TOC]

急需引用命名空间

       
本文是悠闲之余学习Linq的产物。代码是花了差不多十七日的业余时间组织的,敲出来只是为着铭记它。本文使用的Linq查询包罗了三种格局,1种是一直询问,另1种是行使System.Linq中定义的恢弘方法开始展览的询问。对于扩张方法查询的点子,使用了大气的Lambda表的是和种类定义的委托Func<T>。不熟习那多个东西的童鞋们能够在本博找到有关的篇章:

       LINQ
定义了用来塑造查询表明式的最主要字。那一个查询表明式能够对数码开始展览采用、过滤、排序、分组和更改。借助各个LINQ 增添,你能够对不相同的数据源使用同壹的询问表明式。

 

1 using System.Linq;

【Lambda表明式学习记录】【Action<T>和Func<T>委托】

       固然你能够在大肆地方使用 LINQ
,然则只有 ASP.NET 应用程序中最大概把 LINQ
用作数据库组件的一有的。你可以和 ADO.NET 数据访问代码一同使用 LINQ
,或许借助 LINQ to Entities 庖代 ADO.NET 数据访问代码。

1、LINQ 函数

接下来我们要求预加防范数据

一、策动供查询的数据 

 

壹.壹、查询结果过滤 :where()


Enumerable.Where() 是LINQ
中央银行使最多的函数,大多数都要对准会集对象举行过滤,因而Where()在LINQ
的操作上各方可知,Where()的关键职务是担负过滤集结中的数据:其原型如下:

1 public static IEnumerbale<TSouce> Where<TSource>(this IEnumerable<Tsource> source,Func<TSource,bool> predicate);
2 public static IEnumerable<TSource>where<TSource> (this IEnumerable<TSource> source,Func<TSource,int,bool> predicate);

 

   Where()的参数是用来过滤成分的基准,它须要标准必须传回bool,以鲜明此因素是不是符合条件,或是由特定的成分开头算起(使用Func<TSource,int bool>,中间的扩散参数代表该因素在聚集中的索引值),比方要在二个数列集结中找寻超过5的数字时:

1 List<int> list1=new List<int>(){6,4,2,7,9,0};
2  
3 list1.Where(c=>c>5);

 

或者

1 list1.Where(c=>c>=1).Where(c=>c<=5);
2  
3 list1.Where(c=>c>=1&&c<=5); 

 

 Where()的推断规范是,只要判定函数重回true 就营造,反之则打消。

武林高手类

本文首先营造一个提供数据的实体类供之后的询问利用。本文使用的实体类包括了1948到二零零六年超级方程式锦标赛的季军车队和季军赛手。那个数量是应用了实体类和列表来筹算的。

LINQ 基础

       接近 LINQ 最简便易行的办法时领会它是如何针对内部存款和储蓄器集结专业的,那就是LINQ to Objects,最简易款式的 LINQ。

 

       就精神来说,LINQ to Objects 能够使用证明性的 LINQ
表达式替代逻辑(如 foreach 块):

EmployeeDB db = new EmployeeDB();

protected void btnForeach_Click(object sender, EventArgs e)

{

    List<EmployeeDetails> employees = db.GetEmployees();

    List<EmployeeDetails> matches = new List<EmployeeDetails>();

    foreach (EmployeeDetails employee in employees)

    {

        if (employee.LastName.StartsWith("D"))

        {

            matches.Add(employee);

        }

    }

    gridEmployees.DataSource = matches;

    gridEmployees.DataBind();

}

 

protected void btnLINQ_Click(object sender, EventArgs e)

{

    List<EmployeeDetails> employees = db.GetEmployees();

    IEnumerable<EmployeeDetails> matches;

    matches = from employee in employees

              where employee.LastName.StartsWith("D")

              select employee;

    gridEmployees.DataSource = matches;

    gridEmployees.DataBind();

}

金沙澳门官网7817网址 1

 

一.2、选择数据: Select()、SelectMany()


     平时在编写LINQ
函数调用时较少用到选拔数据的函数(因为函数调用会直接回到IEnumerable<T>金沙澳门官网7817网址
群集对象 ),但在编写LINQ语句时非平日用,在讲话中若编写了select new命令,它会被编写翻译器转变到LINQ
Select(),Select() 的原型如下:

1 public static IEnumerable<TResult> Select<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,TResult> selector);
2 public static IEnumerable<TResult> Select<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,int,TResult> selector);

 

      与Where()类似,Select() 也可以按照元素所在的位置判断处理,而Select()所指定的处理式selector 必须传回一个对象,这个对象可以是现有的类型,也可以是匿名的类型,既可以通过Select() 来重新组装所需数据。例:

1 var query=db.OrderDetails.Where(o=>o.ID==12345).Select(o=>new{ ProductID=o.ProductID,Qty=o.Qty});

 

     
Select()的另叁个形似函数SelectMay()则是拍卖有五个汇集对象来源的多少选用,其原型如下:

1     public static IEnumerable<TResult> SelectMany<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,IEnumberable<TResult>> selector);
2     public static IEnumerable<TResult> SelectMany<TSource,TResult>(this IEnumerable<TSource> source,Func<TSource,int,IEnumberable<TResult>> selector);
3     public static IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(this IEnumerable<TSource> source,Func<TSource,IEnumberable<TCollection>> collectionSelector,Func<TSource,TCollection,TResult> resultSelector);
4     public static IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(this IEnumerable<TSource> source,Func<TSource,int,IEnumberable<TCollection>> collectionSelector,Func<TSource,TCollection,TResult> resultSelector);

 

      SelectMany() 在LINQ 函数调用上较难理解,但如果把它想象成数据库

CROSS JOIN ,相对来说就便于懂了,例: 

1 List<int> list1=new List<int>(){1,2,3,4,5,6};
2 List<int> list2=new List<int>(){6,4,2,7,9,0};
3  
4 var query=list1.SelectMany(o=>list2);
5 foreach(var q in query)
6      Console.WriteLine("{0}",q);

 

      输出结果:

1 6424790642790642790642790642790642790

 

      因为“642790”出口了 5回,list壹内的因素是五个,所以能够知晓SelectMany()会遵纪守法list一内的因素个数调用它的selector,并建构群集输出。

 

/// <summary>
/// 武林高手类
/// </summary>
class MartialArtsMaster
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string MenPai { get; set; }
    public string Kongfu { get; set; }
    public int Level { get; set; }

    public override string ToString()
    {
        return string.Format("{0}--{1}--{2}--{3}--{4}--{5}", ID, Name, Age, MenPai, Kongfu, Level);
    }
}

先是定义代表赛手的实业类Racer。Racer类定义了多少个本性和一个重载的ToString()方法,该办法以钦定的格式显示赛手。Racer类达成了IFormattable接口,以帮助格式字符串的分歧变体。这一个类还得以完结类IComparable<T>接口,用以依照赛手的LastName进行排序。为了施行高档查询Racer类同时涵盖了单值属性如FirstName、LastName、Wins(获胜次数)、Country(国籍)和Starts。同时也包含了多值属性如:Cars(赛手在获得季军的年份所使用的赛车)和Years(赛手获得亚军的年度,赛手能够频仍到手亚军)。这一个类具体的贯彻如下:

推迟试行

       使用 foreach 块的代码和接纳 LINQ
表明式的代码的一个肯定的区分在于它们管理相配群集类型格局。对于 foreach
,相配的集聚被创立为一个特定项目标聚集(强类型 List<T>),在 LINQ
的示范中,相配的联谊仅经过它所落成的 IEnumerable<T> 接口暴光。

       爆发那种差异的原委在于 LINQ
使用了推迟施行。只怕和您预期的区别,相配的目的并不是三个饱含了协作的
EmployeeDetails 对象的直观会集,而是三个奇怪的 LINQ
对象,能够在你供给的时候抓取数据。

       依赖查询表明式的不等,LINQ
表明式能够回来不相同的对象,比如:WhereListIterator<T>、UnionIterator<T>、SelectIterator<T>
等,因为经过 IEnumerable<T>
接口和结果相互,因而不须要知道代码所采纳的现实性迭代类。

 

壹.3、群组数据:GroupBy()、ToLookup()


   
 汇总的数量据是查询机制的基本成效,而在集聚以前,必供给先将数据做群组化,才具张开总结,LINQ
的群组数据功能由Enumerable.GroupBy()函数提供。

     GroupBy()
会遵照给定的key(keySelector)以及内容(elementSelector),发生群组后的结果(IGroup接口对象恐怕由resultSelector变迁的结果对象),例:

 1 List<int> sequence =new List<int>(){1,2,3,4,3,2,4,6,4,2,4};
 2  
 3 var group=sequence.GroupBy(o=>o);
 4 foreach(var g in group)
 5 {
 6      Console.WrilteLine("{0} count:{1}",g.Key,g.Count());
 7 /*计算每个数出现的次数。
 8      GroupBy 设置了使用数列本身值作为Key值,并且利用这个Key 分组产生分组的数据(IGrouping<TKey,TElement类型),再对分组的数据进行汇总。结果如下:
 9  
10 1 count: 1
11 2 count: 3
12 3 count: 2
13 4 count: 4
14 6 count: 1
15 
16 */

 

     倘若想要在重返之前对分组后的成分做管理,能够流传elementSelector
而如若要在要素管理后发生结果的话,则可以流传resultSelector,那样回去的会集会是以resultSelector
再次回到的品类为主,而不是暗中同意的IGroup接口。

   
 除了GroupBy()能群组化数据外、其余一个装有群组化数据技能的是ToLookUp(),它能够生成具备群组化特性的会集对象,由ILookup<TKey,TElement>组成。

   
ToLookup()看起来和GroupBy()有点近乎,不过它会此外生成八个新的聚焦对象,那些集结对象由ILookup<TKey,TElement>所组成,允很多个键值存在,且叁个键值可含蓄众多提到的实值。例:

 1 var nameValuesGroup=new[]
 2 {
 3      new{name="Allen", value=65,group="A"},
 4      new{name="Abbey",value=120,group="B"},
 5      new{name="Sue",Value=200,group="A"}
 6 };
 7 var lookupValues=namValuesGroup.ToLookup(c=>c.group);
 8 foreach(var g in lookupValues)
 9 {
10      Console.WriteLine("===Group: {0}===",g.Key);
11      foreach(var item in g)
12      {
13           Console.WriteLine("name:{0},value:{1}",item.name,item.value);
14      }
15 }

 

      GroupBy()自个儿装有延缓施行的特色,而ToLookup()未有。

武林绝学类

Racerusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyLinqTest
{
    [Serializable]
    public class Racer : IComparable<Racer>, IFormattable
    {
        public Racer(string firstName = null,
            string lastName = null,
            string country = null,
            int starts = 0,
            int wins = 0,
            IEnumerable<int> years = null,
            IEnumerable<string> cars = null)
        {
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Country = country;
            this.Starts = starts;
            this.Wins = wins;
            var yearsList = new List<int>();
            foreach (var year in years)
            {
                yearsList.Add(year);
            };
            this.Years = yearsList.ToArray();

            var carList = new List<string>();
            foreach (var car in cars)
            {
                carList.Add(car);
            }
            this.Cars = carList.ToArray();
        }

        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Wins { get; set; }
        public string Country { get; set; }
        public int Starts { get; set; }
        public string[] Cars { get; private set; }
        public int[] Years { get; private set; }

        public override string ToString()
        {
            return String.Format("{0} {1}", FirstName, LastName);
        }

        public string ToString(string format)
        {
            return ToString(format, null);
        }

        public string ToString(string format, IFormatProvider formatProvider)
        {
            switch (format)
            {
                case null:
                case "N":
                    return ToString();
                case "F":
                    return FirstName;
                case "L":
                    return LastName;
                case "C":
                    return Country;
                case "S":
                    return Starts.ToString();
                case "W":
                    return Wins.ToString();
                case "A":
                    return String.Format("{0} {1}, {2}; starts: {3}, wins: {4}",
                          FirstName, LastName, Country, Starts, Wins);
                default:
                    throw new FormatException(String.Format("Format {0} not supported", format));
            }
        }

        public int CompareTo(Racer other)
        {
            if (other == null)
            {
                throw new ArgumentNullException("Other");
            }
            return this.LastName.CompareTo(other.LastName);
        }
    }
}

LINQ 是怎样行事的

  • 要动用 LINQ ,需求创设二个 LINQ 表明式
  • LINQ 表明式的重返值是叁个兑现了 IEnumerable<T> 的迭代器对象
  • 对迭代器对象举办枚举时,LINQ 试行它的干活

       问:LINQ 是何许实行表明式的?为了爆发过滤结果,它到底做了怎么?

       答:依靠你所查询的数据类型的分歧而各异。LINQ to Entities 把 LINQ
表明式调换为数据库命令,所以 LINQ to Entities
须要展开三个数据库连接并实践三回数据库查询以博得你所请求的数额。假诺是前一个演示中采纳的是
LINQ to Objects,LINQ 实施的进程就大致多了,实际上此时 LINQ
只是使用了七个 foreach 循环彻头彻尾遍历集结。

 

一.肆、联接数据: Join() 与GroupJoin()


   
 身为贰个询问机制,将五个集聚进行连接(join)也是本来的,特别是在进展多少的对照和聚集时,联接机制显得更主要。在LINQ
函数中,有 Enumerable.Join() 函数担负管理联接,其原型如下:

public static IEnumerable<TResult> Join<TOuter,TInner,TKey,TResult>(this IEnumerable<TOuter> outer,IEnumerable<TInner> inner,Func<TOutput,TKey> outerKeySelector,Func<TInner,TKey> innerKEySelector,Func<TOuter,TInner,TResult> resultSelector)

 

 

     由原型可看出它将原本的联谊视为TOuter,而将盛传的集纳视为TInner,儿还要调节由哪位属性或成员当Key,最终由resultSelector来输出联接的结果。例:

1 var query=from item1 in list1
2      join item2 in list2 on item1 equals item2
3      select item2;
4 var query3=list1.Join(
5      list2,
6      item1=>item1,
7      item2=>item2,
8      (item1,item2)=>item2
9      );

 

     Enumerable<T>.Join()采纳的是INNER JOIN的概念,当TInner.Key
TOuter.Key平等时,才会将成分输出到resultSelector 作为参数。

     近日常用的连通格局,INNER JOINEnumerable<T>.Join()
实现,CROSS JOINEnumerable<T>.SelectMany() 达成,还有壹种JOIN
形式尚未设想,LEFT OUTER JOIN格局,要得以落成这几个方式,必须求依据GroupJoin()办法来兑现。

    GroupJoinJoin() 11分相似,然而它却又Join()
GroupBy()两方的效劳,在Join() 的情形下,它会留下TInner
TOuter两边都有的值,但在GroupJoin(),它会将TOuter
的值作为Key,并依此来对TInner 做群组化后输出,例:

1 var query4=from item1 in list1
2           join item2 in list2 on item1 equals item2 into g
3           from item in g.DefaultIfEmpty()
4           select new{ v=item1,c=item};
5 var query5=list1.GroupJoin(
6           list2,
7           item1=>item1,
8           item2=>item2,
9           (item1,item2)=>new {v=item1,c=item2.Count()});

 

 
class Kongfu
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int Power { get; set; }

    public override string ToString()
    {
        return string.Format("{0}--{1}--{2}", ID, Name, Power);
    }
}

 

LINQ 表达式

       固然再度调解了子句的一一,但 LINQ 表明式和 SQL
查询表面上照旧很相似。

       持有 LINQ
表达式都必须有1个点名数据源的 from 子句并有二个代表要拿走的多寡的
select 子句(或许1个定义了数据要放入组的 group 子句)。

       from 子句要放在最终面,from
子句明确了两片段消息。紧随 in 之后的单词评释了数据源,紧随 from
之后的单词为数据源中的各样个体提供三个字母:

matches = from employee in employees

       下边是叁个粗略的 LINQ 查询,从 employees 集合中获取具有数据:

matches = from employee in employees

          select employee;

提示:

       能够在微软的 10壹 LINQ
示例中()找到各类表明式的以身作则。

 

1. 投影

       可以修改 select 子句获取一组数据。

// Sample 1

IEnumerable<string> matches;

matches = from employee in employees

          select employee.FirstName;

 

// Sample 2

IEnumerable<string> matches;

matches = from employee in employees

          select employee.FirstName + employee.LastName ;

 

       当您选中新闻时,能够对数值数据或字符串数据应用规范的 C#
操作符对齐实行修改。更风趣的是,能够动态定义贰个新类以封装再次来到的音讯。C#
无名类能够成功那或多或少,技艺是向 select 子句中加多1个 new
关键字并把挑选的始末以目的的款型赋给属性:

var matches = from employee in employees

              select new { First = employee.FirstName, Last = employee.LastName };

       那么些表明式在推行的时候回来一组隐式创制的类的对象。你不晤面到类的定义并且无法把实例传给方法调用,因为它由编写翻译器生成,并且有着活动创制的悬空的称号。可是,你能够在本地使用该类,访问
First 和 Last 属性,以致结合数据绑定使用它(此时 ASP.NET
使用反射依照属性名称获取相应的值)。

       把正在询问的数码调换为种种协会的力量被喻为投影。

       引用独立的靶子也要运用重要字 var ,举个例子对后边的结果举行迭代:

foreach (var employee in matches)

{

    // 可以读取 First 和 Last

}

 

      
当然了,实践投影的时候,并非只可以利用无名氏类。你可以正式定义类型,然后在表明式中采纳它:

public class EmployeeName

{

    public string FirstName { get; set; }

    public string LastName { get; set; }

 

    public EmployeeName(string firstName, string lastName)

    {

        this.FirstName = firstName;

        this.LastName = lastName;

    }

}

 

IEnumerable<EmployeeName> matches = from employee in employees

    select new EmployeeName { FirstName = employee.FirstName, 

    LastName = employee.LastName };

       上述的表达式之所以能够专门的学业,是因为 FirstName 和
LastName 属性能够被集体访问且不是只读的。
始建 EmployeeName
对象后 LINQ 设置那一个属性。此外,你也能够在 EmployeeName
类名称后的括号里为参数化的构造函数提供任何的参数:

IEnumerable<EmployeeName> matches = from employee in employees

        select new EmployeeName(employee.FirstName, employee.LastName);

 

 

二. 过滤和排序

IEnumerable<EmployeeDetails> matches;

matches = from employee in employees

          where employee.LastName.StartsWith("D")

          select employee;

       where 子句接受1个尺码表达式,它针对种种连串进行总计。假使结果为
true ,该类型就被含有到结果中。可是,LINQ
使用相同的延期实行模型,也等于说,直到对结果集举办迭代时才会对 where
子句进行总括。

 

      
你大概早就猜到,能够用逻辑与(&&)以及逻辑或(||)操作符组合三个规格表明式并且能够选用关系操作符(如
<、<=、>、>=):

IEnumerable<Product> matches;

matches = from product in products

          where product.UnitsInStock > 0 && product.UnitPrice > 3.00

          select product;

 

       LINQ
表明式二个妙不可言的风味是让您可见时刻调用自个儿的措施。比如,能够创设一个检查职员和工人的函数
TestEmployee(),依据它是还是不是在结果集中重回 true 或 false:

private bool TestEmployee(EmployeeDetails employee)

{

    return employee.LastName.StartsWith("D");

}

       然后,能够这么使用:

IEnumerable<EmployeeDetails> matches;

matches = from employee in employees

          where TestEmployee(employee)

          select employee;

 

       orderby 操作符一样很直观。它的模子基于 SQL
里的询问语句。你倘使为排序提供2个或七个以逗号分隔的值列表(最后可加
decending 降序):

IEnumerable<EmployeeDetails> matches;

matches = from employee in employees

          orderby employee.LastName,employee.FirstName

          select employee;

注解:

       具备完成了 IComparable
的项目都帮助排序,它是 .NET 最中央的数据类型之壹(如
数值、日期、字符串)。你也得以传递多少个自定义的 IComparable
对象对数码实行排序。

 

一.伍、数据排序:OrderBy() 与ThenBy()


     数据排序是在数码管理中广泛的功力,在LINQ
内的排序主若是以OrderBy函数为主,而为了帮助三番五次条件的排序,可增进ThenBy
函数,以便管理多种原则排序的急需。基于LINQ的推迟查询机制,排序也不是在1始发就进展的,而是在多少真的被访问时才会开始展览排序。因而OrderBy()在处理会集时,传递回来的是称呼IOrderedEnumerable<T>
接口的靶子。

   
 OrderByThenBy再有四个貌似的艺术,差异只在于做反向排序。OrderByDescending
ThenByDescending

     观望函数的原型,会开采OrderBy盛传的是IEnumerable<T>
,但ThenBy传播的是IOrderedEnumerable,所以一般在排序时先调用OrderBy,再使用ThenBy进展多种排序。假诺多个集结有A和B多个属性,若是想要先为A排序再为B排序,则要动用OrderBy(A).ThenBy(B)的方法来实行排序,OrderByThenBy3次调用只好设置一个字段,在展开多种标准时,必须先调用OrderBy,再按供给调用ThenBy一回或频仍。例:

 1  var nameValues=new[]
 2 {
 3      new {name="Allen",value=64},
 4      new {name="abbey",value=120},
 5      new {name="slomng",value=330},
 6      new {name="george",value=213}
 7 };
 8 //single sort
 9 var sortedNames=nameValues.OrderBy(c=>c.name);
10 var sortedValues=nameValues.OrderBy(c=>c.value);
11  
12 //multiply sort conditions
13 var sortedByNameValues=nameValues.OrderBy(c=>c.name).ThenBy(c=>c.value);
14 var sortedByValueNames=nameValues.OrderBy(c=>c.value).ThenBy(c=>c.name);

 

     
假若要安装多种排序条件,请务必使用OrderBy()加上ThenBy()的组合,若使用OrderBy +OrderBy
组合,会使得排序被施行三次,最后的结果会是最终一个OrderBy
所发出的的结果。

Main方法里的武林好手列表和武林绝学列表

第一个实体类是Team。这几个类富含了车队亚军的名字和获取季军的年份。

三. 分组和集聚

       分组令你把大批量的音信浓缩为轻易的大约。

       分组是1种影子,因为结果集中的靶子和数据源集合中的对象是不雷同的。比方,若是你正在管理一组
Product 对象,并操纵把它们放到一定价格的组中。最后的结果是分组对象的
IEnumerable<T>
集结,当中每一种对象表示有个别价格区间内的一定产品。各种组完毕 System.Linq 命名空间的
IGrouping<T,K> 接口。

       使用分组,首先须求做多少个调整:

  • 创设分组的尺码
  • 各类组展现怎么消息

       第二个职分相比较轻便。使用 group、by 以及 into
关键字采用要分组的靶子,分明什么分组并决定引用每种分组时要运用的字母:

var matches = from employee in employees

              group employee by employee.TitleOfCourtesy into g

              ...

// 在 LINQ 中使用 g 作为分组假名是一个常见的约定

 

      
具备同等数量的靶子被安放了同三个组里。要把数量按数值范围开始展览分组,要求编写制定1段总结代码以便为各种组发生一样的数值。例如,要把产品按每一个价位间距是
50 元 实行分组:

var matches = from product in products

              group product by (int)(product.UnitPrice / 50) into g

              ...

       以后,全数多少个低于 50 元的产品的分组键为 0,而价格在 50 – 100
之间的出品的分组键为 一,就那样推算。

       获得分组后,还要鲜明分组的结果回到什么样的音讯。每一个组以达成了
IGrouping<T,K> 接口的靶子的样式暴光给代码。比方,前多少个表明式创建IGrouping<int,Product>
类型的组,也等于说,分组的键值类型是整形,而里面包车型客车成分类型是 Product

       IGrouping<T,K>
接口只提供3本性质 Key ,它用于重回创设组的值。举个例子,若是要创立呈现各样TitleOfCourtesy 组的 TitleOfCourtesy
的字符串列表,应该运用那样的表明式:

var matches = from emp in employees

              group emp by emp.TitleOfCourtesy into g

              select g.Key;

金沙澳门官网7817网址 2

提示:

       对于这么些示例,也能够应用
IEnumerable<string> 代替 var
关键字,因为最后的结果是一两种字符串。然后,日常在分组查询中选择 var
关键字,因为普通需求动用投影和无名氏类获取更加多立竿见影的汇总音信。

 

       其余,也足以回来整个组:

var matches = from emp in employees

              group emp by emp.TitleOfCourtesy into g

              select g;

       那对数码绑定未有其余用处。因为
ASP.NET
不可见显得关于各种组的其他有用音信。但是,它让您能够很方便的对各种组的数目进行自由迭代:

foreach (IGrouping<string, EmployeeDetails> group in matches)

{

    foreach (EmployeeDetails emp in group)

    {

        // do something

    }

}

       那段代码表明就是成立了组,仍是能够够灵活的访问组里的每一个门类。

 

       从更实用的角度来讲,能够应用聚合函数对组里的多少进行计算。LINQ
聚合函数模仿了过去恐怕已用到的数据库聚合函数,允许对组中的成分举行本事和聚集,获取最小值、最大值及平均值。

      
上面包车型大巴以身作则重返1个无名氏类型,它包括分组的键值以及分组中目标的个数,使用多少个放到的方式Count():

var matches = from emp in employees

              group emp by emp.TitleOfCourtesy into g

              select new { Title = g.Key, Employees = g.Count() };

金沙澳门官网7817网址 3

 

      
上二个演示有少数亟待注意,它应用了三个扩充方法。从本质上说,扩大方法是
LINQ 的1组基本功用,它们不是透过专门的 C#
操作符公开,而是必要直接调用这几个主意。

      
扩大方法和平日方法的分别在于扩展方法不是概念在选拔该方式的类里。LINQ
有一个 System.Linq.Enumerable
类,它定义了几十一个扩展方法,这一个主意可被抱有实现了 IEnumerable<T>
的对象调用。

       除了 Count(),LINQ
还定义了汪洋可在分组中运用的强有力的扩展方法,举例聚合函数
马克斯()、Min()、Average()等。使用了那一个艺术的 LINQ
表明式会愈发复杂,因为它们还运用了另二个被叫做 lambda 表达式的 C#
天性,它同意为扩充方法提供其余参数。对于
马克斯()、Min()、Average(),lambda 表明式允许你钦命用于总结的习性。

       那几个示例用于计算每种项目中项指标最高价格、最低价位以及平均价格:

var categories = from p in products

                 group p by p.Category into g

                 select new

                 {

                     Category = g.Key,

                     MaxPrice = g.Max(p => p.UnitPrice),

                     MinPrice = g.Min(p => p.UnitPrice),

                     AvgPrice = g.Average(p => p.UnitPrice)

                 };

 

1.陆、获取集合


     LINQ 所拍卖的数码都由集合而来,因而将LINQ
实施的结果调换到集结也很轻松。LINQ自个儿帮忙种种区别的集合生成方式,包涵生成数组的ToArray()、生成列表的ToList、生成字典集合的ToDictionary
以及改造Lookup<TKey,TElement>类的ToLookup。例:

1 var arrayOutput=nameValues.ToArray();
2 var listOutput=nameValues.ToList();
3  
4 var dictOutput1=nameValues.ToDictionary(c=>c.name);
5 var dictOutput2=nameValues.ToDictionary(c=>c.name,c=>value);

 

List<MartialArtsMaster> masterList = new List<MartialArtsMaster>()
{
    new MartialArtsMaster() { ID = 1, Name = "黄蓉", Age = 18, MenPai = "丐帮", Kongfu = "打狗棒法", Level = 86 },
    new MartialArtsMaster() { ID = 2, Name = "洪七公", Age = 70, MenPai = "丐帮", Kongfu = "打狗棒法", Level = 10 },
    new MartialArtsMaster() { ID = 3, Name = "郭靖", Age = 22, MenPai = "丐帮", Kongfu = "降龙十八掌", Level = 10 },
    new MartialArtsMaster() { ID = 4, Name = "任我行", Age = 50, MenPai = "明教", Kongfu = "葵花宝典", Level = 10 },
    new MartialArtsMaster() { ID = 5, Name = "东方不败", Age = 35, MenPai = "明教", Kongfu = "葵花宝典", Level = 540 },
    new MartialArtsMaster() { ID = 6, Name = "林平之", Age = 23, MenPai = "华山", Kongfu = "葵花宝典", Level = 404 },
    new MartialArtsMaster() { ID = 7, Name = "岳不群", Age = 50, MenPai = "华山", Kongfu = "葵花宝典", Level = 40 },
    new MartialArtsMaster() { ID = 8, Name = "令狐冲", Age = 23, MenPai = "华山", Kongfu = "独孤九剑", Level = 4045 },
    new MartialArtsMaster() { ID = 9, Name = "梅超风", Age = 45, MenPai = "桃花岛", Kongfu = "九阴真经", Level = 078 },
    new MartialArtsMaster() { ID = 10, Name = "黄药师", Age = 28, MenPai = "梅花岛", Kongfu = "弹指神功", Level = 78 },
    new MartialArtsMaster() { ID = 11, Name = "风清扬", Age = 46, MenPai = "华山", Kongfu = "独孤九剑", Level =78 },
};
List<Kongfu> kongfuList = new List<Kongfu>()
{
    new Kongfu() {ID=1,Name="打狗棒法",Power=100 },
    new Kongfu() {ID=1,Name="降龙十八掌",Power=45 },
    new Kongfu() {ID=1,Name="葵花宝典",Power=75 },
    new Kongfu() {ID=1,Name="独孤九剑",Power=45 },
    new Kongfu() {ID=1,Name="九阴真经",Power=39 },
    new Kongfu() {ID=1,Name="弹指神功",Power=2 }
};
Racerusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyLinqTest
{
    [Serializable]
    public class Team
    {
        public Team(string name,params int[] years)
        {
            this.Name = name;
            this.Years = years;
        }
        public string Name { get; private set; }
        public int[] Years { get; private set; }
    }
}

揭秘 LINQ 表达式

       就算 LINQ 使用了新的 C# 关键字(如 from、in 和
select),但这个根本字的贯彻是由其他类提供的。实际上,怀有的 LINQ
查询都被撤换为1组方法的调用。除了正视调换,还足以一向调用这一个方法:

var matches = from emp in employees

              select emp;

 

// 上面的表达式可以改写成这样:

var matches = employees.Select(employee => employee);

       这里所用的语法不太宽广。代码看起来像是在调用 employees 群集的
Select()方法。可是,employees 集结是三个一般性的 List<T>
会集,它并从未包涵这么些主意。相反,Select()是几个恢宏方法,它被电动提须求全数的
IEnumerable<T> 类。

 

1. 恢弘方法

      
扩张方法让你能够在二个类里定义方法,然后就像是它也在其余类里定义了那么调用它。LINQ
扩大方法定义在了 System.Linq.Enumerable 类里,但是富有的
IEnumerable<T> 对象都可调用。

注解:

       因为 LINQ 扩张方法是概念在
System.Linq.Enumerable 类里的,由此该类必须处于可用范围。

       查看一下 Select()方法的概念:

public static IEnumerable<TResult> Select<TSource, TResult>(

    this IEnumerable<TSource> source, Func<TSource, TResult> selector)

{ ... }

       扩张方法必要遵守一些规则:

  • 享有的扩充方法都必须是静态的
  • 扩充方法可用返重播4的数据类型并得以接收率性个数的参数
  • 第3个参数必须是对调用扩大方法的目的的引用(并且从前跟着关键字
    this)
  • 该参数的数据类型决定了扩张方法可用的类

       Select()方法能够被全数落成了 IEnumerable<T>
的类的示范调用(this IEnumerable<TSource> source
参数决定)。另二个参数,用于获取正在挑选的音讯段的信托。重返值是1个IEnumerable<T> 对象。

 

 

2. lambda 表达式

       lambda 表明式在 C#
里是基于方法的 LINQ 表达式的新语法。
lambda 表明式像这么传递给
Select()方法:

matches = employees.Select(employee => employee);

       当 Select()被调用时,employees
对象作为第三个参数字传送递,它是询问的源。第四个参数要求2个对准某些方法的寄托。那些形式实践选用任务,且被集结里的种种成分调用。

      
Select()方法接收一个信托。你能够提供3个无独有偶委托(它指向定义在类里的其余地点的命名方式),但诸如此类做的话会令你的代码变的冗长。

       贰个更轻松的消除办法是行使佚名格局,无名格局以 delegate
开始,然后是艺术签字的声明,随后的花括号里是该方式的代码。要是选拔无名氏格局,前边的示范看起来应当是以此样子的:

IEnumerable<EmployeeDetails> matches = employees

    .Select(

        delegate(EmployeeDetails emp)

        {

            return emp;

        }

    );

 

       lambda 表明式正是让这类代码看起来更为简便易行的一种模式。lambda
表明式由以 =>
分隔的两局地构成。第壹片段代表无名方式接收的参数,对于这几个示例,lambda
表明式接搜聚合里的各个对象并因此名字为 employee 的引用揭破它们。lambda
表明式的第三有的定义要回去的值。

       上面那几个显式的 LINQ 表明式从每一个 employee
里析取数据并封装成3个无名类型再次回到:

var matches = employees

    .Select(

            delegate(EmployeeDetails employee)

            {

                return new

                {

                    First = employee.FirstName,

                    Last = employee.LastName

                };

            }

    );

       未来,你能够用 lambda 表明式来简化代码:

var matches = employees.Select(employee =>

    new { First = employee.FirstName, Last = employee.LastName });

 

3. Multipart 表达式

       当然,许多 LINQ
表明式要比大家这边讲过的以身作则尤其盘根错节。2个一发实际的 LINQ
表明式恐怕会到场排序或过滤。

       比如上面那段代码:

matches = from employee in employees

          where employee.LastName.StartsWith("D")

          select employee;

       能够用显示的语法把那几个表达式重写为:

matches = employees

    .Where(employee => employee.LastName.StartsWith("D"))

    .Select(employee => employee);

       显式 LINQ
语法的3个便宜是它使操作符顺序特别明白。对于前贰个演示,能够很了解的看看它从
employees 集结起来,然后调用 Where(),最后调用
Select()。若是要动用越多的操作符,将会见临越来越长的一组方法调用。

       Where()提供2个 lambda
表明式验证每一个成分,假设它应当包蕴在结果中,则赶回 true。

       Select()提供多个 lambda
表明式用于把各类数据项转变为您期望的款式。

 

       超越八分之四动静下,都应用隐式语法创设LINQ
表达式。可是,偶尔依旧要用到显式语法。比方,需求向扩展方法传递3个不被隐式
LINQ 语法帮助的参数时。

       知情表明式怎样映射到方法的调用、扩张方法如何绑定到
IEnumerable<T> 对象、lambda
表明式如何封装过滤、排序、投影等。这一个使得 LINQ
的里边职业细节变得明掌握白。

壹.7、划分并得到集结


     Skip()SkipWhile()Take()
TakeWhile()。在数据库查询时,为了达成最棒的品质,在数据量大时要举行分页管理(paging)。下面多少个函数的效应正是在大集结内切出小量数码。

 1 public static IEnumberable<TSource> Skip<TSource>(
 2      this IEnumerable<TSource> source,
 3      int count
 4 )
 5 public static IEnumberable<TSource> SkipWhile<TSource>(
 6      this IEnumerable<TSource> source,
 7      Func<TSource,bool> predicate
 8 )
 9 public static IEnumberable<TSource> SkipWhile<TSource>(
10      this IEnumerable<TSource> source,
11      Func<TSource,int ,bool> predicate
12 )
13 public static IEnumberable<TSource> Take<TSource>(
14      this IEnumerable<TSource> source,
15      int count
16 )
17 public static IEnumberable<TSource> TakeWhile<TSource>(
18      this IEnumerable<TSource> source,
19      Func<TSource,bool> predicate
20 )
21 public static IEnumberable<TSource> TakeWhile<TSource>(
22      this IEnumerable<TSource> source,
23      Func<TSource,int ,bool> predicate
24 )

 

      Skip()用来在集合中踊跃,让LINQ
宗旨直接将游标跳到钦定的岗位,而不用经过“巡航”来运动,在巨型集合中可节约不知凡几岁月,而SkipWhile
也有同样功效,但多了判定式,相当于跳过符合条件的成分,而各异的SkipWhile()可用来调整要跳过符合条件的大概判定跳过一定的索引值。

     Take()用来传播集结中一定数量的成分,它会告诉LINQ
宗旨直接回到它所钦命的要素数量,很符合利用与分页的成效。TakeWhile
则是和SkipWhile 类似都以多了规范剖断式,可是TakeWhile
在要素满意条件时,就赶回该因素或是符合一定的索引值条件时回来该因素。

 

 

 

一.八、访问成分


   
 IEnumerable<T>自家正是会晤对象,所以针对集结对象所须求的成分访问也是不可或缺的效应,LINQ里的因素访问成效是推断容器内是或不是带有成分等。

     首先是获得首尾的要素,分别由First()
以及Last()多个法子担任,它们还各有一个姐妹方法FirstOrDefault()以及LastOrDefault()前者若未有第三个或最终1个成分时,会传来null,而后者会传回其品种的私下认可值(基本上正是default(T)的结果)。

     FirstOrDefault() 以及
LastOrDefault()都尚未提供暗中同意的装置格局,因此若想要使用非default(T)的暗中同意值,要动用DefaultEmpty()来设置。First()
Last() 都能流传判定成分是不是符合条件的参数,当规则判别存在时,First
会从集合的先头伊始扫描,并再次来到扫描到符合条件的率先个要素,Last
则是扭曲从集结的尾端初叶扫描,并回到扫描到符合条件的首先个因素。例:

1 var firstLastItems=new []{"zero","two","three","four","five"};
2 string firstContainsO=firstLastItems.First(s=>s.Contains('o'));
3 string lastContainsO=firstLastItems.Last(s=>s.Contains('0'));

 

  LINQ
内还有三个Single,他会在群集中唯有二个成分时传回该因素,但若集结是空的只怕有五个以上的因素时会调用例外管理,或是使用它的姐妹方法SingleOrDefault
传回null值,实用性比fisrt和last 低。

     LINQ
提供了ElementAt()其1法子,可比照索引值访问成分,他有个一般方法ElementAtOrDefault作用和firstordefault/lastordefault
是一样的。当找不到成分时就重返暗中认可值。例:

1 var firstLastItems=new []{"zero","two","three","four","five"};
2 string itematThree=firstLastITems.ElementAt(2);

 

      若要判别群集内有未有特定值,LINQ 提供了Contains,
能够看清集结捏有没有传播的因素,但因为Contain
会判定目的是还是不是等于,所以它此外提供了3个可传唱IEqualityComparer<T>
的当作相比较依附的重载(overload)方法,可用于自定义类对象的十分比较操作。

     若要看清集结内有未有值,LINQ 提供了三个艺术,贰个是Count(),
另四个是Any(),除了能够轻便推断集结内有未有值外,也得以流传决断标准来决定是或不是要列入总计。日常会习贯使用Count
来判定集结内是还是不是留存任何因素,为何要多做二个Any啊。其实是牵记到LINQ
恐怕的查询对象会蕴藏远程数据库,不料定唯有本地的数据源。对于远程的数据源,要是使用Count
,要开支较高的资金财产来读取数据后开始展览计数在流传,但只要使用Any(),则远程只要判定符合条件的数量是还是不是留存一笔就可以,无需总体计数,所以针对中长途数据源,使用Any
来推断有无数据是较好的挑三拣4。针对地点的集合 any 和count 差不多无差别。

     若要一口咬住不放会集内的因素是还是不是全体相符特定条件时, 可以动用LINQ 的All(),
它能够遵从传入的尺码来围观全数因素,唯有在有着因素都符合条件时,或是集结时间和空间时才会回来true
,不然会回去false。

     若要依照成分的类型进行筛选的话,除了使用Where
对每一个成分做类型信息决断外,LINQ 也提供了二个更便捷的主意
OfType<T>(),它能够传回集结内符合T所钦定项目标音信,那么些主意很吻合用在汇集内含有了已兑现了过多接口的类对象。然后采纳OfType<T>依据接口类型进行筛选。

     OfType<T>还有一个接近措施Cast<T>
,功能与OfType <T>相同,但Cast<T>会总结把集合内的因素类型转变来T类型,若不可能开始展览类型调换时会调用InvalidCastException
例外管理。若使用OfType<T>则不会掀起不相同管理。

 

表明式基本写法

其三个类是Formula一.那些类定义方法GetChampions方法再次来到1组表示以及方程式赛车季军的列表。

1.玖、聚合与聚集


     聚合运算(aggregation)是汇集数据管理的第叁职能之1,基本的Max
,Min ,Sum ,Average 以及可协调制定聚合规则的Aggregate()

     Aggregate
是可暂存每一步总结结果的方法,它同意技师遵照传入的条件对每种集合内的要素实行测算,而在每便调用时,他都会将前三次的结果暂存起来,并视作下次总计的散布参数。Aggregate
基本上产生二种事业,第3种是一贯依据传入的口径来拍卖一齐运算;第二种是可在调用时传出2个种子值(seed),这几个种子值会在起初张开演算时作为基准使用,之后可遵照第三遍对种子值的运算方式开始做累计运算;第两种则是在传诵在此以前做最后的管理,例:

 1 double myBalance=100.0;
 2  
 3 int[] withdrawItems={20,10,40,50,10,70,30};
 4  
 5 double balance=withdrawItems.Aggregate(myBalance,(originbalance,nextWithdrawal)=>{
 6      Console.WriteLine("originbalance:{0},nextWithdrawak:{1}",originbalance,nextdrawal);
 7      Console.WriteLine("Withdrawal status:{0}",(nextWithdrawal<=originbalance)?"OK":"FAILED");
 8  
 9      return ((nextWithdrawal<=originbalance)?(originbalance-nextWithdrawal):originbalance);
10 });
11 Console.WriteLine("Ending balance:{0}:",balance);

 

 若要对最后的储蓄值实行管理,就能够使用第四个参数resultSelector,例:

 

1 var balanceStatus=
2 withdrawItems.Aggregate(myBalance,(originbalance,nextWithdrawal)=>{
3      return((nextWithdrawal<=originbalance)?(originbalance-nextWithdrawal):originbalance);
4  
5 },
6 (finalbalance)=>
7 {
8      return (finalbalance>=1000)?"Normal":"Lower";
9 });

 

 

var res = from m in masterList
        where m.MenPai == "丐帮"//条件,布尔表达式
        select m.Name;//返回名字的集合
Racerusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyLinqTest
{
    public static class Formula1
    {
        private static List<Racer> racers;

        public static IList<Racer> GetChampions()
        {
            if (racers == null)
            {
                racers = new List<Racer>();
                racers.Add(new Racer("Nino", "Farina", "Italy", 33, 5, new int[] { 1950 }, new string[] { "Alfa Romeo" }));
                racers.Add(new Racer("Alberto", "Ascari", "Italy", 32, 10, new int[] { 1952, 1953 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Juan Manuel", "Fangio", "Argentina", 51, 24, new int[] { 1951, 1954, 1955, 1956, 1957 }, new string[] { "Alfa Romeo", "Maserati", "Mercedes", "Ferrari" }));
                racers.Add(new Racer("Mike", "Hawthorn", "UK", 45, 3, new int[] { 1958 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Phil", "Hill", "USA", 48, 3, new int[] { 1961 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("John", "Surtees", "UK", 111, 6, new int[] { 1964 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Jim", "Clark", "UK", 72, 25, new int[] { 1963, 1965 }, new string[] { "Lotus" }));
                racers.Add(new Racer("Jack", "Brabham", "Australia", 125, 14, new int[] { 1959, 1960, 1966 }, new string[] { "Cooper", "Brabham" }));
                racers.Add(new Racer("Denny", "Hulme", "New Zealand", 112, 8, new int[] { 1967 }, new string[] { "Brabham" }));
                racers.Add(new Racer("Graham", "Hill", "UK", 176, 14, new int[] { 1962, 1968 }, new string[] { "BRM", "Lotus" }));
                racers.Add(new Racer("Jochen", "Rindt", "Austria", 60, 6, new int[] { 1970 }, new string[] { "Lotus" }));
                racers.Add(new Racer("Jackie", "Stewart", "UK", 99, 27, new int[] { 1969, 1971, 1973 }, new string[] { "Matra", "Tyrrell" }));
                racers.Add(new Racer("Emerson", "Fittipaldi", "Brazil", 143, 14, new int[] { 1972, 1974 }, new string[] { "Lotus", "McLaren" }));
                racers.Add(new Racer("James", "Hunt", "UK", 91, 10, new int[] { 1976 }, new string[] { "McLaren" }));
                racers.Add(new Racer("Mario", "Andretti", "USA", 128, 12, new int[] { 1978 }, new string[] { "Lotus" }));
                racers.Add(new Racer("Jody", "Scheckter", "South Africa", 112, 10, new int[] { 1979 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Alan", "Jones", "Australia", 115, 12, new int[] { 1980 }, new string[] { "Williams" }));
                racers.Add(new Racer("Keke", "Rosberg", "Finland", 114, 5, new int[] { 1982 }, new string[] { "Williams" }));
                racers.Add(new Racer("Niki", "Lauda", "Austria", 173, 25, new int[] { 1975, 1977, 1984 }, new string[] { "Ferrari", "McLaren" }));
                racers.Add(new Racer("Nelson", "Piquet", "Brazil", 204, 23, new int[] { 1981, 1983, 1987 }, new string[] { "Brabham", "Williams" }));
                racers.Add(new Racer("Ayrton", "Senna", "Brazil", 161, 41, new int[] { 1988, 1990, 1991 }, new string[] { "McLaren" }));
                racers.Add(new Racer("Nigel", "Mansell", "UK", 187, 31, new int[] { 1992 }, new string[] { "Williams" }));
                racers.Add(new Racer("Alain", "Prost", "France", 197, 51, new int[] { 1985, 1986, 1989, 1993 }, new string[] { "McLaren", "Williams" }));
                racers.Add(new Racer("Damon", "Hill", "UK", 114, 22, new int[] { 1996 }, new string[] { "Williams" }));
                racers.Add(new Racer("Jacques", "Villeneuve", "Canada", 165, 11, new int[] { 1997 }, new string[] { "Williams" }));
                racers.Add(new Racer("Mika", "Hakkinen", "Finland", 160, 20, new int[] { 1998, 1999 }, new string[] { "McLaren" }));
                racers.Add(new Racer("Michael", "Schumacher", "Germany", 250, 91, new int[] { 1994, 1995, 2000, 2001, 2002, 2003, 2004 }, new string[] { "Benetton", "Ferrari" }));
                racers.Add(new Racer("Fernando", "Alonso", "Spain", 132, 21, new int[] { 2005, 2006 }, new string[] { "Renault" }));
                racers.Add(new Racer("Kimi", "Räikkönen", "Finland", 148, 17, new int[] { 2007 }, new string[] { "Ferrari" }));
                racers.Add(new Racer("Lewis", "Hamilton", "UK", 44, 9, new int[] { 2008 }, new string[] { "McLaren" }));
            }
            return racers;
        }

        private static List<Team> teams;
        public static IList<Team> GetConstructorChampions()
        {
            if (teams == null)
            {
                teams = new List<Team>()
                {
                    new Team("Vanwall", 1958),
                    new Team("Cooper", 1959, 1960),
                    new Team("Ferrari", 1961, 1964, 1975, 1976, 1977, 1979, 1982, 1983, 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008),
                    new Team("BRM", 1962),
                    new Team("Lotus", 1963, 1965, 1968, 1970, 1972, 1973, 1978),
                    new Team("Brabham", 1966, 1967),
                    new Team("Matra", 1969),
                    new Team("Tyrrell", 1971),
                    new Team("McLaren", 1974, 1984, 1985, 1988, 1989, 1990, 1991, 1998),
                    new Team("Williams", 1980, 1981, 1986, 1987, 1992, 1993, 1994, 1996, 1997),
                    new Team("Benetton", 1995),
                    new Team("Renault", 2005, 2006 )
                };
            }
            return teams;
        }
    }
}

二、规范的查询操作符

 

骨子里,条件语句是能够用多个信托代表的,如下边包车型大巴代码

 

2.1 筛选


    例:搜索赢得至少一伍场较量的碧玺和奥地利共和国(Republik Österreich)赛车手。代码如下:

1 var racers=from r in Formula1.GetChampions()
2           where r.Wins > 15 && (r.Country=="Brazil"||r.Country=="Austria")
3           select r;
4  
5 foreach(var r in racers)
6 {
7      Console.WriteLine("{0:A}",r);
8 }

 

      下边采取Where()  和 Select() 的代码:

1 var racers=Formula1.GetChampions().
2           Where(r=>r.Wins>15 && (r.Country=="Brazil" || r.Country=="Austria")).
3           Select(r=>r);

 

 

delegate bool BoolDel(MartialArtsMaster mar);

1 var res = from m in masterList
2         where boolDel(m)
3         select m.Name;

本条类还定义了三个主意:GetConstructorChampions()。用于重返全体车队季军的列表。

二.2 用索引筛选


     无法接纳LINQ 查询的三个例子是Where 方法的重载。在Where
方法的重载中,能够传递第3个参数——索引。索引是筛选器再次来到各种结果的计数器。可以在表明式中央银行使那个目录,
施行基于索引的企图。上面包车型客车代码由Where
扩充方法调用,它使用索引重临姓氏以“A” 起头,索引为偶数的赛车手。

1 var racers=Formula1.GetChamptions().
2           Where((r,index)=>r.LastName.StartsWith("A") && index % 2 !=0);
3  
4 foreach(var r in racers)
5 {
6      Console.WriteLine("{0,A}",r);
7 }
8  

 

也得以行使扩充方法的不二等秘书技打开询问

        二、System.Linq中的扩大方法 

2.3 类型筛选


   
 为了拓展基于项目的筛选,能够运用OfType扩充方法。这里数组数据包罗string
和 int 对象。
使用OfType推而广之方法,把string类传递给泛型参数,就从集结中回到字符串。

1 object[] data={"ones",1,3,"fre","fdfs",333};
 2 var query=data.OfType<string>();
 3 foreach(var s in query)
 4 {
 5      Console.WriteLine(s);
 6 }
 7  /*
 8      运行结果为:
 9  
10 ones
11 fre
12 fdfs
13 */

 

 

var res = masterList.Where(new Func<MartialArtsMaster, bool>(boolDel));

      
扩张方法的功用是将艺术写入最初并未有定义该措施的类中。仍是能够将艺术加多到达成某些特定接口的别样类中,那样多少个类就能够运用同样的兑当代码。对于扩张方法本文不做详细介绍,只是扩张方法在Linq查询中动用较多须要事先领悟。越发是System.Core程序集下定义的System.Linq方法。本文后面将会用到。

2.4 复合的from 子句


   
 假使急需依附目的的二个成员举办筛选,而该成员本身是贰个多种,就足以使用复合的from
子句。Racer 类定义了三性情质Cars,其中Cars
是3个字符串数组。要筛选驾车法拉利的有所季军,能够动用如下所示的LINQ
查询。第一个from子句访问从Formula1.GetChampion()主意重返的Race
对象,首个from 子句访问Racer的 Cars 属性。以回到全体string
类型的赛车。接着在where 子句中运用这一个赛车筛选开车Ferrari的富有季军。

1 var ferrariDrivers=from r in Formula.GetChampions()
2                     from c in r.Cars
3                     where c=="Ferrari"
4                     orderby r.LastName
5                     select r.FirstName +" "+ r.LastName;

 

     C# 编写翻译器把符合的from 子句和LINQ 查询调换为SelectMany
增添方法。个中实例所用的重载版本如下

1 public static IEnumerable<TResult> SelectMany<TSource,TCollection,TResult>(this IEnumerable<TSource> source,Func<TSource,IEnumberable<TCollection>> collectionSelector,Func<TSource,TCollection,TResult> resultSelector);

 

     第一个参数是隐式参数,它从 Get.Champions()方法中接收Racer 对象序列。第二个参数是collectionSelector委托,其中定义了内部序列。在Lambda 表达式 r=>r.Cars 中,应返回赛车集合。第三个委托参数是一个委托,现在为每个赛车调用给委托,接收Racer 和Car 对象。Lambda 表达式创建了以匿名类型,他有Racer 和 Car 类型。 这个SelectMany方法的结果是摊平了赛车手和赛车的层次结构,为每辆赛车返回匿名类型的一个新对象集合。

 

1 var ferrariDrivers= Formula1.GetChampion().
2                     SelectMany(r=>r.Cars,
3                          (r,c)=>new{Racer=r,Car=c}.
4                          where(r=>r.Car=="Ferrari").
5                          OrderBy(r=>r.Racer.LastName).
6                          Select(r=>r.Racer.FirstName+" "+r.Racer.LastName));

 

进而笔者用下边包车型客车代码输出

        三、使用Linq实行查询 

2.5 排序


  要对队列排序,前面使用了 orderby
子句。上面复习一下前面使用的orderby descending
子句的例证。当中赛车手依照赢得竞赛的次数进行降序排序,赢得比赛的次数用关键字选取器钦赐。

1 var racers=from r in Formula1.GetChampions()
2            where r.Country=="Brazil"
3            orderby r.Wins descending
4            select r;

 

     orderby
子句解析为OrderBy( ) 方法,orderby descending子句解析为OrderByDescending方法

 

1 var racers= Formula1.GetChampions().
2           Where(r=>r.Country=="Brazil").
3           OrderByDescending(r=>r.Wins).
4           Select(r=>r);

 

     使用LINQ
查询时,只需把装有用于排序的两样首要字(用逗号隔断)加多到orderby子句中。在下例中,全部的赛车手先根据国家排序,再依照姓氏排序,最终根据名字排序。增添到LINQ
查询结果中的Take()庞大方法用于提取前13个结实:

 

1 var racers=(from r in Formula1.GetChampions()
2                orderby r.Country,r.LastName,r.FirstName
3                select r).Take(10);

 

     使用OrderByThenBy扩展方法可以进行同样的操作

1 var racers=Formula1.GetChamptions().
2      OrderBy(r=>r.Country).
3      ThenBy(r=>r.LastName).
4      ThenBy(r=>r.FirstName).
5      Take(10);

 

 

1 Console.WriteLine("找到 " + res.Count() + " 条记录:");
2 foreach(var item in res)
3 {
4     Console.WriteLine(item);
5 }

有了那一个打算知识和实体类,大家就足以接纳Linq进行询问了。

2.6 分组


     要基于三个注重字值对查询结果分组,能够采取group子句。
今后一级方程式亚军应该遵照国家分组,并列出三个国度的亚军数。子句group r by r.County into g根据
Country 属性组合具有的赛车手,并定义二个新的标记符g
它之后用于访问分组的结果音讯。group子句的结果应该依照使用到分组结果上的增添方法Count来排序,借使季军数同样,就依靠首要字排序,该重大字是国家,因为那是分组使用的重要性字。where
子句根据至少有两项的分组来筛选结果。select
子句创造二个带CountryCount品质的无名类型。

 

 1 var countries= from r in Formula1.GetChampions()
 2                group r by r.Country into g
 3                orderby g.Count() descending, g.Key
 4                where g.Count() >=2
 5                select new {
 6                               Country=g.Key,
 7                               Count=g.Count()
 8                          };
 9 foreach(var item in countries)
10 {
11      Console.WriteLine("{1,-10} {1}",item.Country,item.Count);
12 }

 

     

     接下来把子句
group r by r.Country into g解析为GroupBy(r=>r.Country),重返分组体系。分组连串首先用OrderByDescending格局排序,再用ThneBy
方法排序。接着调用WhereSelect 方法

1 var countries= Formula1.GetChampions().
2                GroupBy(r=>r.Country).
3                OrderByDescending(g=>g.Count()).
4                ThenBy(g=>g.Key).
5                Where(g=>g.Count()>=2).
6                Select(g=>new {Country=g.Key,Count=g.Count()});

 

 

金沙澳门官网7817网址 4

       1、轻易的筛选

二.七 对嵌套的靶子分组


   
 假诺分组的目的应涵盖嵌套的类别,就可以退换select子句制造的无名类型。在上面包车型客车事例中,所再次来到的国度不光应涵盖国家名和赛车手数量那三个天性,还应蕴含赛车手名种类。那几个队列用一个给予Racers属性的from/ in
内部子句钦命,内部的from
子句使用分组标志符g赢得该分组中的全数赛车手,用姓氏对它们排序,再根据姓名创造三个新字符串。

     

 1 var countries=from r in Formula1.GetChampions()
 2                group r by r.Country into g
 3                orderby g.Count() descending, g.Key
 4                where g.Count()>=2
 5                select new
 6                {
 7                     Country=g.Key,
 8                     Count=g.Count(),
 9                     Racers=from r1 in g
10                            orderby r1.LastName
11                            select r1.FirstName +" "+ r1.LastName
12                };
13 foreach(var item in countries)
14 {
15      Console.WriteLine("{0,-10} {1}",item.Country,item.Count);
16      foreach(var name in item.Racers)
17      {
18           Console.WriteLine("{0};",name);
19      }
20      Console.WirteLine(); 
21 }

 

 

联机查询

采用Where子句能够对数据源举办轻便的筛选。下变例子是寻觅最少获得一五场竞技的奥地利(Austria)司机:

2.8 内连接


     使用join
子句可以凭借特定的口径合并几个数据源,但在此以前要收获多个要连续的列表。在一级方程式竞赛中,有赛车手亚军和车队亚军。赛车手从GetChampions
方法中回到,车队从GetConstructionChampions方式中回到。今后要博取八个年份列表,列出每年的跑车手季军和车队季军。

 

 1 var racers= from r in Formula1.GetChampions()
 2             from y in r.Years
 3             select new
 4             {
 5                Year=y,
 6                Name=r.FirstName+" "+r.LastName
 7              };
 8  
 9 vat teams=from t in Formula1.GetConstructorChampions()
10           from y in t.Years
11           select new
12           {
13                Year=y,
14                Name=t.Name
15           };
16 var racersAndTeams=(from r in racers
17                     join t in teams on r.Year equals t.Year
18                     select new
19                     {
20                          r.Year,
21                          Champion=r.Name,
22                          Constructor=t.Name
23                     }).Take(10);
24 Console.WriteLine("Year World Champion\t Constructor Title");
25 foreach(var item in racersAndTeams)
26 {
27      Console.WriteLine("{0}:{1,-20} {2}",item.Year,item.Champion,item.Constructor);
28 }

 

 

     或然合并成八个LINQ 查询

 

 1 var racersAndTeams=(from r in
 2                     from r1 in Formula1.GetChampions()
 3                     from yr in r1.Years
 4                     select new
 5                     {
 6                          Year=yr,
 7                          Name=r1.FirstName+" "+r1.LastName
 8                     }
 9                     join t in
10                          from t1 in Formula1.GetConstructorChampions()
11                          from yt in t1.Years
12                          select new
13                          {
14                               Year=yt,
15                               Name=t1.Name
16                          }
17                     on r.Year equals t.Year
18                     orderby t.Year
19                     select new
20                     {
21                          Year=r.Year,
22                          Racer=r.Name,
23                          Team=t.Name
24                     }).Take(10);

 

 

选用五个from in 进行查询

        /// <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);
            }
        }

2.玖 左外连接


     上一个接连示例的出口从一九伍八年上马,因为从那一年开头,才同时有了跑车手亚军和车队季军。赛车手亚军出现的更早一些,是在一9四七年。使用内一而再时,只有找到了万分的笔录才再次回到结果。为了在结果中包蕴全体的年度,能够应用左外联接。左外连接重返右侧系列中的全体成分,尽管它们在左侧的行列中并未相配的要素。

     上边修改前边的LINQ 查询,使用左外连接。左外连接使用 join
子句和DefaultIfEmpty
方法定义。若是查询的左侧(赛车手)未有相配的车队季军,那么就应用DefaultIfEmpty措施定义其出手的私下认可值。

 

 1 var racersAndTeams=
 2      (from r in racers
 3      join t in teams on r.Year equals t.Year into rt
 4      from t in rt.DefaultIfEmpty()
 5      orderby r.Year
 6      select new
 7      {
 8           Year=r.Year,
 9           Champion=r.Name,
10           Constructor=t==null?"no constructor championship":t.Name
11      }).Take(10);

 

 

1 var res = from m in masterList
2         from k in kongfuList
3         where m.Kongfu == k.Name && k.Power > 90
4         select new { master = m, kongfu = k };

 

2.10 组连接


     左外连接使用了组连接和into
子句。它有一部分语法与组连接同样,只可是组连接不利用DefaultIfEmpty方法。

   
 使用组连接时,能够接连不断七个独立的行列,对于个中一个行列中的有些成分,另二个队列中留存对应的八个项列表。

   
 上边包车型地铁以身作则使用了三个独立的行列。1个是前面例子中壹度看过的季军人列车表,另一个是七个ChampionShip项目标集纳。下边包车型大巴代码段显示了Championship类。

 

1 public class Championship
2 {
3      public int Year{get;set;}
4      public string First{get;set;}
5      public string Second{get;set;}
6      public string Third{get;set;}
7 }

 

 

GetChampionships 重回了季军集结

 

 1 private static List<Championship> championships;
 2 public static IEnumerable<Championship> GetChampionships()
 3 {
 4      if(championships == null)
 5      {
 6           championships=new List<Championship>();
 7           championships.Add(new Championship
 8           {
 9                Year=1950,
10                First="Nino Farina",
11                Second="Juan Manuel Fangio",
12                Third="Luigi Fagioli"
13           });
14           championships.Add(new Championship
15           {
16                Year=1951,
17                First="Juan Manuel Fangio",
18                Second="Alberto Ascari",
19                Third="Froliab Gonzalez"
20           });
21      }

 

 

   
 亚军人列车表应与每种季军年份中赢得前三名的赛车手构成的列表组合起来,然后展现每一年的结果。

    RacerInfo类定义了要来得的音信,如下所示:

1 public class RacerInfo
2 {
3      public int Year{get;set;}
4      public int Position {get;set;}
5      public string FirstName{get;set;}
6      public string LastName{get;set;}
7 }

 

     

     使用连接语句能够把三个列表中的赛车手组合起来。

   
 因为亚军人列车表中的每1项都带有多个赛车手,所以率先须要把这几个那几个列表摊平。一种方法是选用SelectMany
方法,该办法运用的Lambda
表明式为季军人列车表中的每一项再次来到包蕴三项的二个列表。在这些Lambda
表明式的完结中,因为RacerInfo 包罗FirstNameLastName
属性,而接受的联谊只包涵带有First 、Second、Third
属性的三个称呼,所以必须拆分字符串,那能够透过扩充方法 FirstName
SecondName 完成。

 

 1 var racers=Formula1.GetChampionships()
 2           .SelectMany(cs=>new List<RacerInfo>()
 3           {
 4                new RacerInfo{
 5                     Year=cs.Year,
 6                     Position=1,
 7                     FirstName=cs.First.FirstName(),
 8                     LastName=cs.Last.LastName()
 9                },
10                new RacerInfo{
11                     Year=cs.Year,
12                     Position=2,
13                     FirstName=cs.Fisrt.FirstName(),
14                     LastName=cs.Last.LastName()
15                },
16                new RacerInfo{
17                     Year=cs.Year,
18                     Position=3,
19                     FirstName=cs.First.FirstName(),
20                     LastName=cs.Last.LastName()
21                }
22           });

 

 

     扩大方法FirstName 和SecondName 使用空格字符拆分字符串:

 

 1 public static class StringExtension
 2 {
 3      public static string FirstName(this string name)
 4      {
 5           int ix=name.LastIndexOf(' ');
 6           return name.Substring(0,ix);
 7      }
 8      public static string LastName(this string name)
 9      {
10           int ix=name.LastIndexOf(' ');
11           return name.Substring(ix+1);
12      }
13 }

 

 

     今后就足以接连七个连串。Formula1.GetChampions 重返八个Racers
列表,racers 变量重临包罗年份、比赛结果和赛车手名字的1个RacerInfo
列表。仅使用姓氏相比较五个聚众中的项是不够的。有时候列表中或者同时涵盖了2个赛车手和她的阿爹,所以必须同时利用FirstName
LastName
进行相比。那是经过为四个列表创立一个新的佚名类型达成的。通过采取into
子句,第贰个聚众中的结果被增多到了变量yearResults中。对于第六个聚众中的各种跑车手,都创设了三个yearResults.
它蕴涵了在其次个汇集中匹配名和姓的结果。最终,用LINQ
查询成立了三个富含所需消息的新佚名类型。

 

 1 var q=(from r in Formula1.GetChampions()
 2           join r2 in racers on
 3           new
 4           {
 5                FirstName=r.FirstName,
 6                LastName=r.LastName
 7           }
 8           equals
 9           new
10           {
11                FisrtName=r2.FirstName,
12                LastName=r2.LastName
13           }
14           into yearResults
15           select new
16           {
17                FirstName=r.FirstName,
18                LastName=r.LastName,
19                Wins=r.Wins,
20                Stars=r.Stars,
21                Results=yearResults
22           });
23 foreach(var r in q)
24 {
25      Console.WriteLine("{0} {1}",r.FirstName,r.LastName);
26      foreach(var results in r.Results)
27      {
28           Console.WriteLine("{0} {1}.",results.Year,results.Position);
29      }
30 }

 

 

动用扩大方法开始展览同步查询

那段代码的功能能够利用System.Linq中的扩充方法来促成:

贰.11 聚集操作


     扩张方法
DistinctUnionIntersectExcept都以集聚操作。下边创造1个驾乘Ferrari的一级方程式亚军系列和精通迈凯伦的超级方程式亚军类别,然后显然是或不是有驾乘法拉利和迈凯伦的季军。

 

1 var ferrariDrivers=from r in
2                     Formula1.GetChampions()
3                     from c in r.Cars
4                     where c =="Ferrari"
5                     orderby r.LastName
6                     select r;

 

 

     今后创建另一个基本同样的询问,但where
子句的参数不一样,以得到全体驾乘迈凯伦的亚军。最佳不要再次编写一样的询问,而得以创立3个艺术,个中给它传递参数
car

 

1 private static IEnumerable<Racer> GetRacersByCar(string car)
2 {
3      return from r in Formula1.GetChampions()
4                from c in r.Cars
5                where c==car 
6                orderby r.LastName
7                select r;
8 }

 

 

   
 但是,因为该方法不必要再别的地点使用,所以\应定义三个寄托项目的变量来保存LINQ
查询,*racerByCar变量必须是贰个寄托项目,该委托类型须求四个字符串参数,并重回IEnumerable<Racer>,类似于前方落成的主意。为此,定义了多少个泛型委托Func<>,
所以没有供给表明本人的嘱托。把2个Lambda
表明式赋予racerByCar变量。拉姆da 表明式的左手定义了一个car
变量。其项目时Func 委托的首先个泛型参数(字符串)。左侧定义了LINQ
查询,它应用该参数和where 子句:

 

1 Func<string , IEnumerable<Racer>> racersByCar=
2                car=>from r in Formula1.GetChampions()
3                     from c in r.Cars
4                     where c==car
5                     orderby r.LastName
6                     select r;

 

 

     今后能够采用Intersect 扩充方法
,获得开车法拉利和迈凯伦的有着季军:

     

1 Console.WriteLine("World champion with Ferrari and McLaren");
2 foreach(var racer in racersByCar("Ferraris").Interesect(racersByCar("McLaren")))
3 {
4      Console.WirteLine(racer);
5 }

 

     

  群集操作通过调用实体类的GetHashCodeEquals
方法来相比对象。对于自定义比较,还足以传递3个落实了IEqualityComparer<T>接口的对象。在这么些示例中,GetChampions措施总是回到同样的对象,由此暗中同意的比较操作时有效的,借使不是那种景色,就足以重载会集方法来自定义比较操作。

 

var res = masterList.SelectMany(m => kongfuList, (m, k) => new { master = m, kongfu = k })
    .Where(x => x.master.Kongfu == x.kongfu.Name && x.kongfu.Power > 90);

【代码】

2.12 合并


    Zip() 方法,允许用二个谓词函数把五个有关的行列合并为多个。

   
 首先,创造两个有关的行列,它们利用同样的筛选和排序方法。对于统一,这很重大,因为第壹个聚众中的第三项会与第三个集聚中的第一项联合,第二个聚众中的第二项会与第叁个聚众中的第二项联合,以此类推。假若七个体系的项数不相同,Zip
方法就在到达一点都不大集结的末尾时停下。

     第3个汇聚中的成分有叁个Name属性,第三个聚众中的成分有LastName
和Starts 四个性子

     在racerNames集结上利用Zip
方法,需求把第二个聚众(racerNamesAndStarts)作为第1个参数。第三个参数的门类时Func<TFirst, TSecond, TResult>
这几个参数落成为三个拉姆da 表明式,它经过参数first
接收第叁个聚众的因素,通过参数second
接收第二个汇聚的要素。其促成代码成立并回到3个字符串,该字符串蕴涵首个汇聚申月素的Name属性和第一个聚众瓜月素的Starts
属性。

 

 1 var racerNames=from r in Formula1.GetChampions()
 2                where r.Country =="Italy"
 3                orderby r.Wins descending
 4                select new
 5                {
 6                     Name=r.FirstName +" "+ r.LastName
 7                };
 8 var racerNamesAndStarts=from r in Formula1.GetChampions()
 9                          where r.Country="Italy"
10                          orderby r.Wins descending
11                          select new
12                          {
13                               LastName=r.LastName,
14                               Starts=r.Starts
15                          };
16 var racers=racerNames.Zip(racerNamesAndStarts,(first,second)=>first.Name+", starts: "+second.Starts);
17 foreach(var r in racers)
18 {
19      Console.WriteLine(r);
20 }

 

 

金沙澳门官网7817网址 5

            var query2 = Formula1.GetChampions()
                .Where(r => r.Country == "Brazil" || r.Country == "Austria")
                .Select(r=>r);

2.13 分区


     扩大方法Take 和Skip
等的分区操作可用于分页,例如在首先个页面上只显示多少个赛车手,在下一个页面上展现接下去的八个赛车手。

     在上边包车型大巴LINQ 查询中,把扩张方法Skip 和Take 增添到查询的末梢。Skip
方法先忽略依据页面大小和骨子里页数总结出的项数,再使用Take()
方法依照页面大小提取一定数量的项。

 

1 int pageSize=5;
 2  
 3 int numberPages=(int)Math.Ceiling(Formula1.GetChampions().Count()/(double)pageSize);
 4 for(int page=0;page<numberPages;page++)
 5 {
 6      Console.WriteLine("Page {0}",page);
 7      var racers=(from r in Formula1.GetChampions()
 8                     orderby r.LastName,r.FirstName
 9                     select r.FirstName+" "+r.LastName).
10                     Skip(page*pageSize).Take(pageSize);
11      foreach(var name in racers)
12      {
13           Console.WriteLine(name);
14       }
15      Console.WriteLine();
16 }
17  

 

   
 那些分页机制的叁个中央是,因为查询会在各类页面上举办,所以改动底层的多少会潜移默化结果。在继续奉行分页操作时,会来得新对象。依照差别的图景,那对于应用程序或许有利于。即使那个操作时无需的,就可以只对原来的数据源分页,然后选择映射导到原来数据上的缓存。

     使用TakeWhileSkipWhile
扩充方法,还是能传递三个谓词,根据谓词的结果提取或跳过好几项。

 

 

 

二.14 聚合操作符


     聚合操作符(如 Count、Sum、 Min、马克斯、Average、Aggregate)
不回去三个系列,而回到三个值。

    Count扩张方法再次回到集合中的项数。上边包车型客车Count 方法应用于Racer 的Year
属性,来筛选赛车手,只回去获得季军次数抢先二回的赛车手,因为同三个询问中须要利用同3个计数超越1遍,所以选拔let
子句定义了二个变量 numberYear

 

 1 var query=from r in Formula1.GetChampions()
 2           let numberYears=r.Years.Count()
 3           where numberYear>=3
 4           orderby numberYears descending, r.LastName
 5           select new
 6           {
 7                Name=r.FirstName+" "+r.LastName,
 8                TimesChampion=numberYears
 9           };
10 foreach(var r in query)
11 {
12      Console.WriteLine("{0} {1}",r.Name,r.TimesChampion);
13 }     
14  

 

     Sum 方法汇总类别中的全部数字,再次回到那个数字的和。上边的Sum
方法用于计算三个国度取得比赛的总次数。首先依照国家对赛车手分组,再在新创设的无名氏类型中,把Wins
属性赋予有些国家取得比赛的总次数。

 

 1 var countries=(from c in from r in Formula1.GetChampions()
 2                group r by r.Country into c
 3                select new
 4                {
 5                     Country=c.Key,
 6                     Wins=(from r1 in c select r1.Wins).Sum()
 7                }
 8                orderby c.Wins descending, c.Country
 9                select c).Take(5);
10 foreach(var country in countries)
11 {
12      Console.WriteLine("{0} {1}",country.Country,country.Wins);
13 }

 

     对于Aggergate艺术,
能够传递三个拉姆da表明式,该表明式对具备的值举办联谊。

 

选用Join on 举行同步查询

注:并不是兼备的询问都足以采取Linq查询大概扩充方法都能够完成的。高等查询要求利用增添方法。

二.一五 调换操作符


   
 前边提到,查询能够顺延到走访数据项时在执行。在迭代中运用查询时,查询会推行。而使用转变操作符会即刻实践查询,把询问结果放在数组、列表或字典中。

     在底下的例子中,调用ToList
扩大方法,立时实践查询,获得的结果放在List<T> 类中。

     

1 List<Racer> racers=(from r in Formula1.GetChampions()
2                     where r.Starts>150
3                     orderby r.Starts descending
4                     select r).ToList();
5 foreach(var racer in racers)
6 {
7      Console.WriteLine("{0} {0:S}",racer);
8 }

 

     

   
 把再次来到的目的放在列表中并从未那么轻巧。比如,对于集结类中从赛车到赛车手的火速访问。能够应用新类Lookup<TKey,TElement>

     

  Dictionary<TKey,TValue>
类只辅助多少个键相应贰个值。在System.Linq名称空间的类Lookup<TKey,TElement>类中,多少个键能够对应七个值。

     使用复合的from 查询,能够摊平赛车手和赛车连串,创造带有Car 和Racer
属性的无名氏类型。在回去的Lookup
对象中,键的品类应是意味着汽车的string,值的门类应是Racer
为了拓展那一个选项,能够给ToLookUp
方法的二个重载版本传递几个键和3个要素选取器。键选用器引用Car
属性镁元素采纳器引用Racer 属性。

 

 1 var racers=(from r in Formula1.GetChampions()
 2                from c in r.Cars
 3                select new
 4                {
 5                     Car=c,
 6                     Racer=r
 7                }).ToLookup(cr=>cr.Car,cr=>cr.Racer);
 8 if(racers.Contains("Williams"))
 9 {
10      foreach(var williamsRacer in Racers["Williams"])
11      {
12           Console.WriteLine(williamsRacer);
13      }
14 }

 

 

     假诺供给在非类型化的聚合上(如ArrayList)使用LINQ
查询,就足以行使Cast
方法。在上面包车型地铁例证中,基于Object类型的ArrayList群集用Racer
对象填充。为了定义强类型化的询问,能够利用Cast 方法

 

 1 var list=new System.Collections.ArrayList(Formula1.GetChampions() as System.Collections.ICollection);
 2  
 3 var query= from r in list.Cast<Racer>()
 4           where r.Country=="USA"
 5           orderby r.Wins descending
 6           select r;
 7 foreach(var racer in query)
 8 {
 9      Console.WriteLine("{0:A}",racer);
10 }

 

 

var res = from m in masterList
        join k in kongfuList on m.Kongfu equals k.Name
        select new { master = m, kongfu = k };

       二、用索引进行筛选

二.1陆 生成操作符

 

变化操作符Range、
Empty、Repear不是扩张方法,而是回到类别的健康静态方法。在LINQ to Objects
中,这么些办法可用于Enumerable 类。

      有时须求填写1个限制的数字,此时就应利用Range
方法,那个形式把第二个参数作为开首值,把第二个参数作为要填写的项数。

1  
2 var values =Enumerable.Range(1,20);
3 foreach(var item in values)
4 {
5      Console.WriteLine("{0}",item);
6 }
7 Console.WriteLine();
8  
9 //结果 1 2 3 4 5 6 ......  19 20

 

 

Range 方法
不回去填充了所定义值的集合,这几个措施与其它艺术同样,也推迟实施查询,并重返1个RangeEnumerator
,个中唯有一条yield return 语句,来递增值。

 

   
 能够把该结果与任何扩张方法统一齐来,获得另1个结果。举例,使用Select
扩大方法

 

1 var values =Enumerable.Range(1,20).Select(n=>n*3);

 

 

     Empty
方法再次来到三个不重回值的迭代器,他得以用来供给二个成团的参数,个中能够给参数传递空会集。

     Repeat 方法重返三个迭代器,该迭代器把同3个值重复特定的次数。 


金沙澳门官网7817网址 6

Where()扩大方法的3个重载中,能够对该方法传递第3个参数:索引。索引是筛选器再次回到的各个结果的计数器,能够在表明式中动用索引,施行一些目录相关的计量。现编的代码应用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);
            }
        }

对查询结果实行排序

       三、筛选出不相同的数据类型

var res = from m in masterList
        orderby m.Level, m.Age descending //级别升序,年龄降序
        select m;

应用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);
            }
        }