从LINQ开始之LINQ to Objects(上)

LINQ概述



  LINQ,语言集成查询(Language Integrated Query),它允许使用C#或VB代码以查询数据库相同的方式来操作不同的数据源。

LINQ体系结构


从上图可以看出,LINQ总共包括五个部分:LINQ to Objects、LINQ to DataSets、LINQ to SQL、LINQ to Entities、LINQ to XML。
LINQ to Objects:对内存中集合的操作
LINQ to DataSets:对数据集Datatable的操作
LINQ to SQL:对SQL Server数据源的操作,微软把开发的重点从LINQ to SQL转移到了LINQ to Entities并且宣布LINQ to SQL不再提供更新
LINQ to Entities:是 Entity Framework的一部分并且取代LINQ to SQL作为在数据库上使用 LINQ的标准机制
LINQ to XML:对XML数据源的操作

LINQ的语法

  下面是一个简单的示例,查询一个int数组中小于5的元素,并按照从小到大的顺序排列:

        int[] arr = new int[] { 1, 4, 2, 6, 7, 9, 5, 1, 2, 4 };
        var query = from r in arr
                    where r < 5
                    orderby r
                    select r;
        foreach (var item in query)
        {
            Console.WriteLine(item);
        }
        Console.ReadLine();

  由此示例可以看出:LINQ查询表达式以from子句开头,以select子句结束。在两个子句之间,可以使用where、orderby等查询操作符。
  LINQ有两种语法:Lambda语法和Query语法,编译器会在程序编译时转换LINQ查询,以调用相应的扩展方法。
以下是LINQ表达式结构示意图:

引用自百度百科

LINQ to Objects



LINQ to Objects中的扩展方法在System.Core程序集的System.Linq命名空间中定义。

Enumerable类定义的标准查询操作符:


下面介绍使用这些操作符的示例:
首先,我们需要创建基本的实体类Employee:

/// <summary>
/// 员工类
/// </summary>
public class Employee
{
    //员工编号
    public string EmployeeId { get; private set; }
    //员工姓名
    public string EmployeeName { get; private set; }
    //年龄
    public int Age { get; private set; }
    //入职日期
    public DateTime EntryDate { get; private set; }
    //性别
    public string Sex { get; private set; }
    //部门
    public string Department { get; private set; }
    //薪水
    public int Salary { get; private set; }
    //爱好
    public IEnumerable<string> Hobby { get; private set; }

     public Employee(string employeeId, string employeeName, int age, DateTime entryDate, Sex sex, Department department, int salary, IEnumerable<string> hobby)
    {
        this.EmployeeId = employeeId;
        this.EmployeeName = employeeName;
        this.Age = age;
        this.EntryDate = entryDate;
        this.Sex = sex.ToString();
        this.Department = department.ToString();
        this.Salary = salary;
        this.Hobby = hobby;
    }
}

//性别
public enum Sex
{
    Male,
    Female
}

//部门
public enum Department
{
    HR,
    IT,
    PD,
    FD,
    QC,
    MD
}

然后,创建列表employees保存10名员工的基本信息:

         List<Employee> employees = new List<Employee>()
        {
            new Employee("001","Mike",32,new DateTime(2016,2,20),Sex.Male,Department.IT,200000,new string[] { "swimming","shopping"}),
            new Employee("002","Jack",38,new DateTime(2007,5,12),Sex.Male,Department.HR,409989,new string[] { "reading"}),
            new Employee("003","Adolph",25,new DateTime(2017,3,23),Sex.Male,Department.IT,100000,new string[] { "play computer games","watch TV","listen to music"}),
            new Employee("004","Antony",30,new DateTime(2010,11,20),Sex.Male,Department.FD,320000, new string[] { "play chess","run"}),
            new Employee("005","Asa",28,new DateTime(2014,10,10),Sex.Female,Department.FD,120000,new string[] { "shopping"}),
            new Employee("006","Bernie",31,new DateTime(2008,4,5),Sex.Male,Department.PD,220000,new string[] { "play basketball"}),
            new Employee("007","Carl",26,new DateTime(2015,1,30),Sex.Male,Department.QC,100000,new string[] { "play chess","go fishing"}),
            new Employee("008","Duncan",30,new DateTime(2009,6,9),Sex.Male,Department.MD,250000,new string[] { "play computer games"}),
            new Employee("009","Aimee",24,new DateTime(2017,1,20),Sex.Female,Department.HR,80000,new string[] { "reading","run"}),
            new Employee("010","Cassie",31,new DateTime(2014,3,3),Sex.Female,Department.IT,350000,new string[] { "watch TV" })
        };

1)筛选操作符(Where、OfType<TResult>)
Where:根据表达式函数过滤元素

        //查询年龄大于30岁,IT或HR部门所有员工的编号及姓名
        var filter = from r in employees
                    where r.Age > 30 && (r.Department == Department.IT.ToString() || r.Department == Department.HR.ToString())
                    select r;

        foreach (var item in filter)
        {
            Console.WriteLine("EmployId: " +item.EmployeeId + " EmployeeName: " + item.EmployeeName);
        }

        //******************************Output*******************************
        //EmployId: 001 EmployeeName: Mike
        //EmployId: 002 EmployeeName: Jack
        //EmployId: 010 EmployeeName: Cassie
        //*******************************************************************

OfType<TResult>:类型筛选

        //筛选出指定数组中所有int类型的元素
        object[] data = { "One", 2, 3, "Four", "Five", 6 };
        var typeFilter = data.OfType<int>();
        foreach (var item in typeFilter)
        {
            Console.WriteLine(item);
        }

        //******************************Output*******************************
        //2
        //3
        //6
        //*******************************************************************

2)投射操作符(Select、SelectMany)
Select:根据选择器函数选择的结果值投射到新的类型元素上
SelectMany:C#编译器把复合的from子句和LINQ查询转换为SelectMany扩展方法,用于迭代序列的序列。

        //查找个人爱好中有reading的员工的姓名
        var doubleFrom = from r in employees
                         from h in r.Hobby
                         where h == "reading"
                         select r.EmployeeName;
        foreach (var item in doubleFrom)
        {
            Console.WriteLine(item);
        }

        //******************************Output*******************************
        //Jack
        //Aimee
        //*******************************************************************

        //--------------------------强势分隔符--------------------------------

        //使用SelectMany扩展方法返回个人爱好中有reading的员工的姓名
        var selectMany = employees.
            SelectMany(r => r.Hobby,
            (r, h) => new { Employee = r, Hobby = h }).
            Where(r => r.Hobby == "reading").
            Select(r => r.Employee.EmployeeName);
        foreach (var item in selectMany)
        {
            Console.WriteLine(item);
        }
        //******************************Output*******************************
        //Jack
        //Aimee
        //*******************************************************************

3)排序操作符(OrderBy、ThenBy、OrderByDescending、ThenByDescending、Reverse)
OrderBy、OrderByDescending:升序排序、降序排序
ThenBy、ThenByDescending:如果第一次排序有元素相同,进行第二次排序(使用LINQ查询时只需把需要排序的关键字用逗号隔开)

        //按照年龄从大到小排序,如果年龄相同,则按照员工编号正向排序,输出员工的编号、姓名、年龄,
        var orderBy = from o in employees
                      orderby o.Age descending, o.EmployeeId
                      select o;
        foreach (var item in orderBy)
        {
            Console.WriteLine("EmployeeId: " + item.EmployeeId + " EmployeeName:" + item.EmployeeName + " Age:" + item.Age);
        }

        //******************************Output*******************************
        //EmployeeId: 002 EmployeeName: Jack Age:38
        //EmployeeId: 001 EmployeeName: Mike Age:32
        //EmployeeId: 006 EmployeeName: Bernie Age:31
        //EmployeeId: 010 EmployeeName: Cassie Age:31
        //EmployeeId: 004 EmployeeName: Antony Age:30
        //EmployeeId: 008 EmployeeName: Duncan Age:30
        //EmployeeId: 005 EmployeeName: Asa Age:28
        //EmployeeId: 007 EmployeeName: Carl Age:26
        //EmployeeId: 003 EmployeeName: Adolph Age:25
        //EmployeeId: 009 EmployeeName: Aimee Age:24
        //*******************************************************************
        //--------------------------强势分隔符--------------------------------
        //使用ThenBy扩展方法实现年龄相同,按员工编号正向排序
        var thenBy = employees
                     .OrderByDescending(t => t.Age)
                     .ThenBy(t => t.EmployeeId)
                     .Select(t => "EmployeeId: " + t.EmployeeId + " EmployeeName:" + t.EmployeeName + " Age:" + t.Age);
        foreach (var item in thenBy)
        {
            Console.WriteLine(item);
        }

        //******************************Output*******************************
        //EmployeeId: 002 EmployeeName: Jack Age:38
        //EmployeeId: 001 EmployeeName: Mike Age:32
        //EmployeeId: 006 EmployeeName: Bernie Age:31
        //EmployeeId: 010 EmployeeName: Cassie Age:31
        //EmployeeId: 004 EmployeeName: Antony Age:30
        //EmployeeId: 008 EmployeeName: Duncan Age:30
        //EmployeeId: 005 EmployeeName: Asa Age:28
        //EmployeeId: 007 EmployeeName: Carl Age:26
        //EmployeeId: 003 EmployeeName: Adolph Age:25
        //EmployeeId: 009 EmployeeName: Aimee Age:24
        //*******************************************************************

Revise:使用扩展方法反转集合中的元素顺序

        //按照年龄从大到小排序后再反转元素的顺序
        var reverse = employees
            .OrderByDescending(r => r.Age)
            .Reverse()
            .Select(r => "EmployeeId: " + r.EmployeeId + " EmployeeName:" + r.EmployeeName + " Age:" + r.Age);
        foreach (var item in reverse)
        {
            Console.WriteLine(item);
        }

        //******************************Output*******************************
        //EmployeeId: 009 EmployeeName: Aimee Age:24
        //EmployeeId: 003 EmployeeName: Adolph Age:25
        //EmployeeId: 007 EmployeeName: Carl Age:26
        //EmployeeId: 005 EmployeeName: Asa Age:28
        //EmployeeId: 008 EmployeeName: Duncan Age:30
        //EmployeeId: 004 EmployeeName: Antony Age:30
        //EmployeeId: 010 EmployeeName: Cassie Age:31
        //EmployeeId: 006 EmployeeName: Bernie Age:31
        //EmployeeId: 001 EmployeeName: Mike Age:32
        //EmployeeId: 002 EmployeeName: Jack Age:38
        //*******************************************************************

4)连接操作符(Join、GroupJoin)
为了完成这部分的示例,我们需要准备新的实体类和列表

/// <summary>
/// 部门信息
/// </summary>
public class DepartmentInfo
{
    //部门编号
    public string DepartmentId { get; private set; }
    //部门名称
    public string DepartmentName { get; private set; }
    //部门总监
    public string Director { get; private set; }

    public DepartmentInfo(string departmentId, string departmentName, string director)
    {
        this.DepartmentId = departmentId;
        this.DepartmentName = departmentName;
        this.Director = director;
    }
}

/// <summary>
/// 杰出团队
/// </summary>
public class OutstandingTeam
{
    public int Year { get; private set; }
    public string Department { get; private set; }

    public OutstandingTeam(int year, string department)
    {
        this.Year = year;
        this.Department = department;
    }
}

创建列表departmentInfo保存各部门的信息

        List<DepartmentInfo> deparmentInfo = new List<DepartmentInfo>()
        {
            new DepartmentInfo("001","HR","Oliver"),
            new DepartmentInfo("002","IT","Oscar"),
            new DepartmentInfo("003","PD","ELLA"),
            new DepartmentInfo("004","FD","Alice"),
            new DepartmentInfo("005","QC","Kai")
        };

创建列表outstandingTeams保存2010年起获得杰出团队的部门

        List<OutstandingTeam> outstandingTeams = new List<OutstandingTeam>()
        {
            new OutstandingTeam(2010,"IT"),
            new OutstandingTeam(2011,"FD"),
            new OutstandingTeam(2012,"HR"),
            new OutstandingTeam(2013,"IT"),
            new OutstandingTeam(2014,"QC"),
            new OutstandingTeam(2015,"HR"),
            new OutstandingTeam(2016,"HR"),
            new OutstandingTeam(2017,"MD")
        };

Join:根据特定的条件合并两个数据源

        //查询员工的姓名,部门以及该部门的总监
        var join = from j in employees
                   join d in deparmentInfo
                   on j.Department equals d.DepartmentName
                   select new
                   {
                       j.EmployeeName,
                       j.Department,
                       d.Director
                   };
        foreach (var item in join)
        {
            Console.WriteLine("EmployeeName: " + item.EmployeeName + " Department:" + item.Department + " Director:" + item.Director);
        }

        //******************************Output*******************************
        //EmployeeName: Mike Department:IT Director:Oscar
        //EmployeeName: Jack Department:HR Director:Oliver
        //EmployeeName: Adolph Department:IT Director:Oscar
        //EmployeeName: Antony Department:FD Director:Alice
        //EmployeeName: Asa Department:FD Director:Alice
        //EmployeeName: Bernie Department:PD Director:ELLA
        //EmployeeName: Carl Department:QC Director:Kai
        //EmployeeName: Aimee Department:HR Director:Oliver
        //EmployeeName: Cassie Department:IT Director:Oscar
        //*******************************************************************

这时候我们会发现,输出的内容里面少了员工Duncan的信息,检查后发现,原来deparmentInfo没有添加MD部门的相关信息,此时希望查询所有员工,若匹配不到该部门信息,Director返回N/A。

        //查询员工的姓名,部门以及该部门的总监,若匹配不到该部门信息,Director返回N/A
        var leftjoin = from j in employees
                       join d in deparmentInfo
                       on j.Department equals d.DepartmentName into jd
                       from d in jd.DefaultIfEmpty()
                       select new
                       {
                           j.EmployeeName,
                           j.Department,
                           Director = d == null ? "N/A" : d.Director
                       };
        foreach (var item in leftjoin)
        {
            Console.WriteLine("EmployeeName: " + item.EmployeeName + " Department:" + item.Department + " Director:" + item.Director);
        }

        //******************************Output*******************************
        //EmployeeName: Mike Department:IT Director:Oscar
        //EmployeeName: Jack Department:HR Director:Oliver
        //EmployeeName: Adolph Department:IT Director:Oscar
        //EmployeeName: Antony Department:FD Director:Alice
        //EmployeeName: Asa Department:FD Director:Alice
        //EmployeeName: Bernie Department:PD Director:ELLA
        //EmployeeName: Carl Department:QC Director:Kai
        //EmployeeName: Duncan Department:MD Director:N/A
        //EmployeeName: Aimee Department:HR Director:Oliver
        //EmployeeName: Cassie Department:IT Director:Oscar
        //*******************************************************************

GroupJoin:基于键相等对两个序列的元素进行关联并对结果进行分组。

        //查找每个部门获得杰出团队的年份
        var groupJoin = from d in deparmentInfo
                        join o in outstandingTeams on d.DepartmentName equals o.Department into g
                        select new
                        {
                            DepartmentName = d.DepartmentName,
                            Years = g
                        };
        foreach (var item in groupJoin)
        {
            Console.WriteLine("Department:" + item.DepartmentName);

            if (item.Years.Count() == 0)
            {
                Console.WriteLine("Never won the award");
            }
            foreach (var champions in item.Years)
            {
                Console.WriteLine(champions.Year);
            }

        }

        //******************************Output*******************************
        //Department: HR
        //2012
        //2015
        //2016
        //Department: IT
        //2010
        //2013
        //Department: PD
        // Never won the award
        // Department:FD
        //2011
        //Department: QC
        //2014
        //*******************************************************************

5)组合操作符(GroupBy、ToLookup)
GroupBy:根据关键字值对查询结果进行分组。

        //查询每个部门及人数
        var groupBy = from e in employees
                      group e by e.Department into g
                      select new
                      {
                          g.Key,
                          Count = g.Count()
                      };
        foreach (var item in groupBy)
        {
            Console.WriteLine("Department: " + item.Key + " Count: " + item.Count);
        }
        //******************************Output*******************************
        //Department: IT Count: 3
        //Department: HR Count: 2
        //Department: FD Count: 2
        //Department: PD Count: 1
        //Department: QC Count: 1
        //Department: MD Count: 1
        //*******************************************************************

ToLookup:通过创建一对多的字典来组合元素

        //使用ToLookup实现爱好阅读的员工姓名
        var toLookup = (from e in employees
                        from h in e.Hobby
                        select new
                        {
                            Hobby = h,
                            Name = e.EmployeeName
                        }).ToLookup(he => he.Hobby, he => he.Name);

        if (toLookup.Contains("reading"))
        {
            foreach (var item in toLookup["reading"])
            {
                Console.WriteLine(item);
            }
        }

        //******************************Output*******************************
        //Jack
        //Aimee
        //*******************************************************************

6)限定操作符(Any、All、Contains)
Any:是否包含满足条件的元素

        //是否有小于20岁的员工
        bool any = employees.Any(r => r.Age < 20);
        Console.WriteLine(any);

        //******************************Output*******************************
        //False
        //*******************************************************************

ALL:是否所有元素都满足条件

        //是否所有员工都大于20岁
        bool all = employees.All(r => r.Age > 20);
        Console.WriteLine(all);

        //******************************Output*******************************
        //True
        //*******************************************************************

Contains:检索某个元素是否在集合中

        //员工列表中是否包含david
        Employee david = new Employee("011", "David", 28, new DateTime(2017, 5, 21), Sex.Male, Department.IT, 100000, new string[] { "run" });
        employees.Add(david);
        bool contains = employees.Contains(david);
        Console.WriteLine(contains);

        //******************************Output*******************************
        //True
        //*******************************************************************

7)分区操作符(Take、Skip、TakeWhile、SkipWhile)
Take:从集合中提取指定数量的元素
Skip:跳过集合中指定数量的元素

        //忽略薪水最高的5位,查询剩余部分薪水最高的员工姓名及薪水
        var skip = (from e in employees
                    orderby e.Salary descending
                    select e).Skip(5).Take(1);
        foreach (var item in skip)
        {
            Console.WriteLine("EmployeeName: " + item.EmployeeName + " Salary: " + item.Salary);
        }

        //******************************Output*******************************
        //EmployeeName: Mike Salary: 200000
        //*******************************************************************

TakeWhile:提取条件为真时的元素

        //取集合中满足条件salary大于1000000之前的所有员工的姓名和薪水
        var takeWhile = (from e in employees
                         select e).TakeWhile(r => r.Salary > 100000);
        foreach (var item in takeWhile)
        {
            Console.WriteLine("EmployeeName: " + item.EmployeeName + " Salary: " + item.Salary);
        }

        //******************************Output*******************************
        //EmployeeName: Mike Salary: 200000
        //EmployeeName: Jack Salary: 409989
        //*******************************************************************

SkipWhere:跳过集合中满足条件的元素,当条件不成立时返回剩余的所有元素

        //跳过集合中满足条件salary大于100000的元素,当条件不成立时返回剩余的所有元素
        var skipWhile = (from e in employees
                         select e).SkipWhile(r => r.Salary > 100000);
        foreach (var item in skipWhile)
        {
            Console.WriteLine("EmployeeName: " + item.EmployeeName + " Salary: " + item.Salary);
        }

        //******************************Output*******************************
        //EmployeeName: Adolph Salary: 100000
        //EmployeeName: Antony Salary: 320000
        //EmployeeName: Asa Salary: 120000
        //EmployeeName: Bernie Salary: 220000
        //EmployeeName: Carl Salary: 100000
        //EmployeeName: Duncan Salary: 250000
        //EmployeeName: Aimee Salary: 80000
        //EmployeeName: Cassie Salary: 350000
        //*******************************************************************

8)Set操作符(Distinct、Union、Intersect、Except、Zip)
Distinct:从集合中删掉重复的元素

        //给所有员工的薪水排序,去掉重复的
        var distinct = (from e in employees
                        orderby e.Salary
                        select e.Salary).Distinct();

        foreach (var item in distinct)
        {
            Console.WriteLine(item);
        }

        //******************************Output*******************************
        //80000
        //100000
        //120000
        //200000
        //220000
        //250000
        //320000
        //350000
        //409989
        //*******************************************************************

Union、Intersect、Except:并集、交集、差集
首先,我们准备两个集合:员工姓名以A开头和员工姓名以E结尾

        var startWithA = (from e in employees
                          where e.EmployeeName.StartsWith("A")
                          select e).ToList();

        var endWithE = (from e in employees
                        where e.EmployeeName.ToUpper().EndsWith("E")
                        select e).ToList();

以下分别取两个集合的并集、交集、差集:

        //查询两个集合的并集
        var union = startWithA.Union(endWithE);
        foreach (var item in union)
        {
            Console.WriteLine(item.EmployeeName);
        }

        //******************************Output*******************************
        //Adolph
        //Antony
        //Asa
        //Aimee
        //Mike
        //Bernie
        //Cassie
        //*******************************************************************

        //--------------------------强势分隔符--------------------------------

        //查询两个集合的交集
        var intersect = startWithA.Intersect(endWithE);
        foreach (var item in intersect)
        {
            Console.WriteLine(item.EmployeeName);
        }

        //******************************Output*******************************
        //Aimee
        //*******************************************************************

        //--------------------------强势分隔符--------------------------------

        //查询两个集合的差集
        var except = startWithA.Except(endWithE);
        foreach (var item in except)
        {
            Console.WriteLine(item.EmployeeName);
        }

        //******************************Output*******************************
        //Adolph
        //Antony
        //Asa
        //*******************************************************************

Zip:把两个集合中对应的项目合并起来,在到大较小集合的末尾时停止

        //把两个集合中对应的项的姓名合并起来
        var zip = startWithA.Zip(endWithE, (first, second) => first.EmployeeName + "+" + second.EmployeeName);
        foreach (var item in zip)
        {
            Console.WriteLine(item);
        }

        //******************************Output*******************************
        //Adolph+Mike
        //Antony+Bernie
        //Asa+Aimee
        //Aimee+Cassie
        //*******************************************************************

9)元素操作符(First、FirstOrDefault、Last、LastOrDefault、ElementAt、ElementAtOrDefault、Single、SingleOrDefault)
First:返回第一个满足条件的元素;若不存在,则引发异常。
FirstOrDefault:返回第一个满足条件的元素;若不存在,则返回默认值。

        //查询年龄大于30岁的第一位员工的姓名
        var first = (from e in employees
                     orderby e.Age
                     select e).First(r => r.Age > 30);
        Console.WriteLine(first.EmployeeName);

        //******************************Output*******************************
        //Bernie
        //*******************************************************************

假设需查询年龄大于50岁的第一位员工的姓名,我们将上述代码中年龄修改为50

        var first = (from e in employees
                     orderby e.Age
                     select e).First(r => r.Age > 50);
        Console.WriteLine(first.EmployeeName);

执行后发现异常

此时使用FirstOrDefault操作符:

        //查询年龄大于50岁的第一位员工的姓名,若不存在,则返回N/A
        var firstOrDefault = (from e in employees
                              orderby e.Age
                              select e).FirstOrDefault(r => r.Age > 50);
        Console.WriteLine(firstOrDefault == null ? "N/A" : firstOrDefault.EmployeeName);

        //******************************Output*******************************
        //N/A
        //*******************************************************************

Last:返回最后一个满足条件的元素;若不存在,则引发异常。
LastOrDefault:返回最后一个满足条件的元素;若不存在,则返回默认值。
ElementAt:返回指定索引位置的元素;若不存在,则引发异常。
ElementAtOrDefault:返回指定索引位置的元素;若不存在,则返回默认值。
Single:只返回一个满足条件的元素;若不存在或多个元素都满足条件,则引发异常。
SingleOrDefault:只返回一个满足条件的元素;若不存在或多个元素都满足条件,则返回默认值。
10)聚合操作符(Count、Sum、Min、Max、Average、Aggregate)
Count:返回集合中的项数

        //查找有一个以上爱好的员工的姓名、爱好的数量及部门
        var count = from e in employees
                    let numberHobby = e.Hobby.Count()
                    where numberHobby > 1
                    select new
                    {
                        e.EmployeeName,
                        numberHobby,
                        e.Department
                    };
        foreach (var item in count)
        {
            Console.WriteLine("EmployeeName: " + item.EmployeeName + " NumberHobby: " + item.numberHobby + " Department: " + item.Department);
        }

        //******************************Output*******************************
        //EmployeeName: Mike NumberHobby: 2 Department: IT
        //EmployeeName: Adolph NumberHobby: 3 Department: IT
        //EmployeeName: Antony NumberHobby: 2 Department: FD
        //EmployeeName: Carl NumberHobby: 2 Department: QC
        //EmployeeName: Aimee NumberHobby: 2 Department: HR
        //*******************************************************************

Sum:计算所有值的总和
Min、Max、Average:最小值、最大值、平均值

        //计算所有员工薪水的总和
        var sum = (from e in employees
                   select e.Salary).Sum/*Min、Max、Average*/();
        Console.WriteLine(sum.ToString("N0"));

        //******************************Output*******************************
        //2,149,989
        //*******************************************************************

Aggregate:对序列进行累加

        //初始值为50000000,依次累加所有员工的薪水
        var aggregate = (from e in employees
                         select e.Salary).Aggregate(5000000, (x, y) => x + y, r => r * 2);
        Console.WriteLine(aggregate.ToString("N0"));

        //******************************Output*******************************
        //14,299,978
        //*******************************************************************

说明:Aggregate扩展方法的第一个参数为初始值。第二个参数是一个表达式,用来对每个元素进行计算(第一个参数是累加变量,第二个参数是当前值)。第三个参数是一个表达式,用来对最终结果进行计算。
11)转换操作符(ToArray、AsEnumerable、ToList、ToDictionary、Cast<TResult>)
使用转换操作符会立即执行查询,将查询结果放在数组、列表、字典中。

        //将年龄大于30岁的元素放入list中再循环输出。
        List<Employee> employeeList = (from e in employees
                                       where e.Age > 30
                                       select e).ToList();
        foreach (var item in employeeList)
        {
            Console.WriteLine("EmployeeName: " + item.EmployeeName + " Age:" + item.Age);
        }

        //******************************Output*******************************
        //EmployeeName: Mike Age:32
        //EmployeeName: Jack Age:38
        //EmployeeName: Bernie Age:31
        //EmployeeName: Cassie Age:31
        //*******************************************************************

12)生成操作符(Empty、Range、Repeat)
生成操作符不是扩展方法,而是返回序列的静态方法。在LINQ to Objects中,这些方法可用于Enumerable类。
Empty:生成空集合

        //生成一个int类型的空序列
        var empty = Enumerable.Empty<int>();
        Console.WriteLine(empty.Count());

        //******************************Output*******************************
        //0
        //*******************************************************************

Range:生成一系列数字的集合

        //生成一个从1开始,10个元素的序列
        var range = Enumerable.Range(1, 10);
        foreach (var item in range)
        {
            Console.WriteLine(item);
        }

        //******************************Output*******************************
        //1
        //2
        //3
        //4
        //5
        //6
        //7
        //8
        //9
        //10
        //*******************************************************************

Repeat:返回始终重复一个值的集合

        //生成一个10个元素,每个元素都是5的序列
        var repeat = Enumerable.Repeat(5, 10);
        foreach (var item in repeat)
        {
            Console.WriteLine(item);
        }

        //******************************Output*******************************
        //5
        //5
        //5
        //5
        //5
        //5
        //5
        //5
        //5
        //5
        //*******************************************************************

本篇就此结束,主要介绍了LINQ的体系结构、基本语法以及LINQ to Obejcts中标准查询操作符的使用方法。
示例代码下载:https://github.com/Answer-Geng/LINQ

时间: 2024-10-21 15:24:52

从LINQ开始之LINQ to Objects(上)的相关文章

从LINQ开始之LINQ to Objects(下)

前言 上一篇<从LINQ开始之LINQ to Objects(上)>主要介绍了LINQ的体系结构.基本语法以及LINQ to Objects中标准查询操作符的使用方法.本篇则主要讨论LINQ to Objects中的扩展方法以及延迟加载等方面的内容. 扩展方法 扩展方法简介 扩展方法能够向现有类型"添加"方法,而无需创建新的派生类型.重新编译或其他方式修改原始类型.扩展方法是静态方法,它是类的一部分,但实际没有放在类的源代码当中.下面,我们来看一个简单示例,为上一篇中定义的

Linq学习(二)-LinQ to Entity

在昨天我学习了LinQ的一些基础知识和动手写了一些LinQ to Object的例子的基础上,对于LinQ语法和基本的要点有了一定的了解.今天继续自己的学习,对于今天学习的LinQ to DataSet 和LinQ to Entity做自己的一些总结,一方面加深自己的理解,另一方面也能掌握LinQ技术的实现机制,对于也跟我一样对着一方面有兴趣的也可以让大家有个初步的感性认识,也是好的. 今天主要的篇幅会讲解LinQ to Entity的C#实现机制以及解决昨天我看完一小节之后的两点疑惑,后面会花

LINQ体验(13)——LINQ to SQL语句之运算符转换和ADO.NET与LINQ to SQL

运算符转换 1.AsEnumerable:将类型转换为泛型 IEnumerable 使用 AsEnumerable<TSource> 可返回类型化为泛型 IEnumerable 的參数.在此演示样例中,LINQ to SQL(使用默认泛型 Query)会尝试将查询转换为 SQL 并在server上运行. 但 where 子句引用用户定义的client方法 (isValidProduct),此方法无法转换为 SQL. 解决方法是指定 where 的client泛型 IEnumerable<

Linq实战 之 Linq to Sql及Entity Framework操作详解

Linq实战 之 Linq to Sql及Entity Framework操作详解 一:linq to db的框架 1. linq to sql 2. linq to ado.net entity framework linq to sql是一个团队 ef 是一个团队... linq to sql => ef 团队. linq to sql 适合一些小型的项目 => sqlserver ef 适合中形的项目,而且可以支持 sqllite,mysql,sqlserver 掌柜的项目开发中:使用的

LINQ系列:LINQ to SQL Exists/In/Any/All/Contains

1. Any 返回没有Product的Category var expr = from c in context.Categories where !c.Products.Any() select c; SELECT [Extent1].[CategoryID] AS [CategoryID], [Extent1].[CategoryName] AS [CategoryName] FROM [dbo].[Category] AS [Extent1] WHERE NOT EXISTS (SELEC

LINQ体验(11)——LINQ to SQL语句之Null语义和String/DateTime方法

在本系列中.主要介绍LINQ to SQL基础的东西,由于LINQ太强大了,它对我们寻常使用不同的数据源有着不同的内容,其包含对于SQL Server 数据库的LINQ to SQL:对于XML 文档的LINQ to XML.对于 ADO.NET 数据集的LINQ to DataSet.对于.NET 集合.文件.字符串等的LINQ to Objects.例外也出现了一些对LINQ支持的开源项目,比如LINQ to JSON,LINQ for NHibernate等等. 在这个系列中,一些关于LI

LINQ体验(9)——LINQ to SQL语句之Insert/Update/Delete操作

我们继续讲解LINQ to SQL语句,这篇我们来讨论Insert/Update/Delete操作.这个在我们的程序中最为常用了.我们直接看例子. Insert/Update/Delete操作 插入(Insert) 1.简单形式 说明:new一个对象,使用InsertOnSubmit方法将其加入到对应的集合中,使用SubmitChanges()提交到数据库. NorthwindDataContext db = new NorthwindDataContext(); var newCustomer

LINQ:介绍 LINQ(目录)

介绍 LINQ(目录) 语言集成查询 (LINQ) 是 Visual Studio 2008 和 .NET Framework 3.5 版中引入的一项创新功能. 传统上,针对数据的查询都是以简单的字符串表示,而没有编译时类型检查或 IntelliSense 支持. 此外,您还必须针对以下各种数据源学习一种不同的查询语言:SQL 数据库.XML 文档.各种 Web 服务等等. 通过LINQ, 您可以使用语言关键字和熟悉的运算符针对强类型化对象集合编写查询. 在 Visual Studio 中,可以

LINQ体验(18)——LINQ to SQL语句之视图和继承支持

视图 我们使用视图和使用数据表类似,只需将视图从"服务器资源管理器/数据库资源管理器"拖动到O/R 设计器上,自动可以创建基于这些视图的实体类.我们可以同操作数据表一样来操作视图了.这里注意:O/R 设计器是一个简单的对象关系映射器,因为它仅支持 1:1 映射关系.换句话说,实体类与数据库表或视图之间只能具有 1:1 映射关系.不支持复杂映射(例如,将一个实体类映射到多个表).但是,可以将一个实体类映射到一个联接多个相关表的视图. 下面使用NORTHWND数据库中自带的Invoices