LINQ学习

1 篇文章 0 订阅
本文详细介绍了LINQ的概念,如何使用SQL风格查询.NET框架中的数据,以及它在委托、匿名方法、Lambda表达式和.NET内置委托类型的应用,涵盖了Where、Count、Any、Select、GroupBy等核心操作及其示例。
摘要由CSDN通过智能技术生成

什么是LINQ

LINQ(读音link)代表语言集成查询(Language Integrated Query),是.NEt框架的扩展,它允许我们用SQL查询数据库的方式来查询数据的集合,使用它,你可以从数据库、程序对象的集合以及XML文档中查询数据

复习委托:

        委托是可以指向方法的类型,调用委托变量时执行的就是变量指向的方法。

using System;
using System.ComponentModel.Design.Serialization;
using System.Runtime.CompilerServices;

namespace ConsoleApp1
    // Note: actual namespace depends on the project name.
{
    class Program
    {
        static void Main(string[] args)
        {
            D1 d = F1;
            d();
            d = F2;
            d();

            D2 d2 = Add;
            Console.WriteLine(d2(3,5));

        }

        static void F1()
        {
            Console.WriteLine(" i am f1");
        }
        static void F2()
        {
            Console.WriteLine(" i am f2");
        }
        static int Add(int x,int y)
        {
            return x + y;
        }
    }
    delegate void D1();
    delegate int D2(int i,int j);

}

         .Net中定义了泛型委托Action(无返回值)和Func(有返回值),所以一般不用自定义委托类型。

        委托变量不仅可以指向普通方法,还可以指向匿名方法。

using System;
using System.ComponentModel.Design.Serialization;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;

namespace ConsoleApp1
// Note: actual namespace depends on the project name.
{
    class Program
    {
        static void Main(string[] args)
        {

            Action f1 = delegate ()
            {
                Console.WriteLine(" ia am rachel");
            };
            f1();
            Action<string, int> f2 = delegate (string n, int i)
            {
                Console.WriteLine($"n={n},i={i}");
            };
            f2("rachel", 18);
            Func<int, int, int> f3 = delegate (int i, int j)
            {
                return i + j;
            };
            Console.WriteLine(f3(3, 5));
        }
    }
}

匿名方法可以写成lambda表达式,可以省略参数数据类型,因为编译能根据委托类型推断出参数类型,用=>引出来方法体

             Func<int, int, int> f3 = delegate (int i, int j)
            {
                return i + j;
            };
            Console.WriteLine(f3(3, 5));

            Func<int, int, int> f4 = (int i, int j)=>
            {
                return i + j;
            };
            Console.WriteLine(f4(5, 8));

 如果委托没有返回值,且方法体只有一行代码,那么{}可以省略

如果=>之后的方法体中只有一行代码,且方法有返回值,那么可以省略方法体的{}以及return.

            Func<int, int, int> f5 = ( i, j) =>
            {
                return i + j;
            };
            Console.WriteLine(f5(5, 8));

            Func<int, int, int> f6 = (i, j) => i + j;
            
            Console.WriteLine(f6(5, 8));

LINQ提供了很多集合的扩展方法,配合lambda能简化数据处理

using System;
using System.Linq;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {

            int[] nums = { 1, 2, 3, 54, 21, 55, 698 };
            //Where方法会遍历集合中每个元素,对于每个元素都调用a=>a>10这个表达式
            //判断一下是否为true,如果都为true,则把这个放到返回的集合中
            //
            IEnumerable<int> result = nums.Where(a => a > 10);
            foreach(int i in result)
            {
                Console.WriteLine(i);
            }

        }
        static IEnumerable<int> MyWhere1(IEnumerable<int> items,Func<int,bool> f) 
        {
            List<int> result=new List<int>();
            foreach(int i in items)
            {
                if(f(i)==true)
                {
                    result.Add(i);
                }
            }
            return result;

        }
        static IEnumerable<int> MyWhere2(IEnumerable<int> items, Func<int, bool> f)
        {
            
            foreach (int i in items)
            {
                if (f(i) == true)
                {
                    yield return i;
                }
            }

        }

    }
}

可以使用var让编辑器的“类型推断” ,来简化类型的声明。在LINQ中常用。

C#的var和JavaScript中的var不一样,仍然是强类型的,C#中的弱类型是dynamic。

LINQ中提供了大量类似Where的扩展方法,简化数据处理,大部分都在System.Linq命名空间中。注意,这些扩展方法都是基于IEumnberable<T>泛型扩展方法。

准备初始数据

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Employee
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public bool Gender { get; set; }
        public int Salary { get; set; }
        public override string ToString()
        {
            return $"Id={Id},Name={Name},Age={Age},Gender{Gender},Salary={Salary}";
        }
    }
}
using System;
using System.Linq;
using System.Net.Cache;
using System.Reflection;
using System.Xml.Linq;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {

          List<Employee> list = new List<Employee>();
            list.Add(new Employee { Id = 1, Name = "rachel", Age = 34, Gender = true, Salary = 3652 });
            list.Add(new Employee { Id = 2, Name = "alan", Age = 28, Gender = true, Salary = 8754 });
            list.Add(new Employee { Id = 3, Name = "daniel", Age = 12, Gender = true, Salary = 3650 });
            list.Add(new Employee { Id = 4, Name = "ben", Age = 22, Gender = false, Salary = 8955 });
            list.Add(new Employee { Id = 5, Name = "normal", Age = 18, Gender = true, Salary = 5000 });
            list.Add(new Employee { Id = 6, Name = "crush", Age = 28, Gender = true, Salary = 2544 });
            list.Add(new Employee { Id = 7, Name = "cornor", Age = 36, Gender = true, Salary = 6000 });
            list.Add(new Employee { Id = 8, Name = "zane", Age = 55, Gender = false, Salary = 5000 });
        }


    }
}

        Where方法:每一项数据都会经过predicate的测试,如果针对一个元素,predicate执行的返回值为true,那么这个元素就会放到返回值中。

        where参数是一个lambda表达式格式的匿名方法,方法的参数e表示当前判断的元素对象。参数的名字不一定非要叫e,不过一般lambda表达式中的变量名长度都不长.

using System;
using System.Linq;
using System.Net.Cache;
using System.Reflection;
using System.Xml.Linq;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {

          List<Employee> list = new List<Employee>();
            list.Add(new Employee { Id = 1, Name = "rachel", Age = 34, Gender = true, Salary = 3652 });
            list.Add(new Employee { Id = 2, Name = "alan", Age = 28, Gender = true, Salary = 8754 });
            list.Add(new Employee { Id = 3, Name = "daniel", Age = 12, Gender = true, Salary = 3650 });
            list.Add(new Employee { Id = 4, Name = "ben", Age = 22, Gender = false, Salary = 8955 });
            list.Add(new Employee { Id = 5, Name = "normal", Age = 18, Gender = true, Salary = 5000 });
            list.Add(new Employee { Id = 6, Name = "crush", Age = 28, Gender = true, Salary = 2544 });
            list.Add(new Employee { Id = 7, Name = "cornor", Age = 36, Gender = true, Salary = 6000 });
            list.Add(new Employee { Id = 8, Name = "zane", Age = 55, Gender = false, Salary = 5000 });

            IEnumerable<Employee> items=list.Where(e => e.Age > 30);
            foreach(Employee e in items){
                Console.WriteLine(e);
            }
        }


    }
}

Count()方法:获取数据条数

             Console.WriteLine(list.Count());
            Console.WriteLine(list.Count(e => e.Age > 30));
            Console.WriteLine(list.Count(e => e.Age > 30&&e.Salary>6000));

Any()方法:是否至少有一条数据满足要求

            Console.WriteLine(list.Any(e=>e.Salary < 6000));

获取一条数据(是否带参数的两种写法):

Single:有且只有一条满足要求的数据;

SingleOrDefault:最多只有一条满足要求的数据;

First:至少有一条,返回第一条

FirstOrDefault:返回第一条或者默认值;


           IEnumerable<Employee> items=list.Where(e => e.Name == "Jerry");
            Employee e1 = items.Single();
           // list.Where(e => e.Name == "Jerry").Single();
            Console.WriteLine(e1);

            Employee e2 = list.Where(e => e.Name == "Jerry").Single();
            Console.WriteLine(e2);

选择合适的方法,“防御性编程”。

排序-Order()对数据进行正序排序

OrderByDescending()倒序排序;

对于简单类型排序,也许不用lambda表达式。特殊案例:按照最后一个字符排序;用Guid或者随机数进行随机排序。

  IEnumerable<Employee> items2 = list.OrderBy(e => e.Salary);
            foreach(Employee e in items2)
            {
                Console.WriteLine(e);
            }

IEnumerable<Employee> items2 = list.OrderByDescenting(e => e.Salary);
            foreach(Employee e in items2)
            {
                Console.WriteLine(e);
            }

int[] nums = new int[] { 3, 9, 8, 10, 7, 6 };
            IEnumerable<int> nums2 = nums.OrderBy(i => i);
            foreach(var i in nums)
            {
                Console.WriteLine(i);
            }

var items3=list.OrderBy(e=>e.Age).ThenByDescending(e=>e.Salary);
            foreach(var e in items3)
            {
                Console.WriteLine(e);
            }

限制结果集,获取部分数据:

Skip(n)跳过n条数据,Take(n)获取n条数据。

案例:获取从第2条开始获取3条数据

//跳过3条数据取出2条数据
            var items4 = list.Skip(3).Take(2);
            foreach (var e in items4)
            {
                Console.WriteLine(e);
            }
var items5 = list.Where(e=>e.Age>30).OrderBy(e=>e.Age).Skip(1).Take(2);
            foreach (var e in items5)
            {
                Console.WriteLine(e);
            }

聚合函数:

Max(),Min(),Average(),Sum(),Count()

LINQ中多有得扩展方法几乎都是针对IEnumberable接口的,而几乎所有能返回集合的都返回IEumerable,所以是可以把几乎所有方法“链式使用”的。

分组:

GroupBy()方法参数是分组条件表达式,返回值为<IGroupingTKey,TSource>类型的泛型IEnumerable,也就是每一组以一个IGrouping对象的形式返回。IGrouping是一个继承自IEnumerable的接口,IGrouping中Key属性表示这一组的分组数据的值。

案例:根据年龄分组,获取每组人数,最高工资,平均工资。用var简化编程。

投影:

把集合中的每一项转换为另外一种类型,按照规则

IEnumerable<int> items6=list.Select(e=>e.Age);
            foreach(int i in items6)
            {
                Console.WriteLine(i);
            }
IEnumerable<string> items7 = list.Select(e => e.Name);
            foreach (string i in items7)
            {
                Console.WriteLine(i);
            }
IEnumerable<string> items8 = list.Where(e=>e.Age>30).Select(e => e.Name+","+e.Age);
            foreach (string i in items8)
            {
                Console.WriteLine(i);
            }
IEnumerable<string> items9 = list.Where(e => e.Salary > 4000).Select(e => e.Gender?"男":"女");
            foreach (string i in items9)
            {
                Console.WriteLine(i);
            }
IEnumerable<Dog> items10 = list.Select(e =>new Dog{Nickname=e.Name,Age=e.Salary});
            foreach (Dog d in items10)
            {
                Console.WriteLine($"{d.NickName},{d.Age}");
            }
var items11 = list.GroupBy(e => e.Age).Select(g => new { NianLing=g.Key,MaxS=g.Max(e=>e.Salary),MinS=g.Min(e1=>e1.Salary),Renshu=g.Count()});
            foreach (var e in items11)
            {
                Console.WriteLine(e.NianLing+","+e.MaxS+","+e.MinS+","+e.RenShu);
            }

集合转换:

有一些地方需要数组类型或者List类型的变量,我们可以用ToArray()方法和ToList()分别把IEnumerable<T>转换为数组类型和List<T>类型。

            IEnumerable<Employee> item1 = list.Where(e => e.Salary > 6000);
            List<Employee> list2=item1.ToList();
            Employee[] array2=item1.ToArray();

链式调用:

Where,Select,OrderBy,GroupBy,Take,Skip等返回值都是IEnumerable<T>类型,所以可以链式调用,案例:

        获取Id>2的数据,然后按照Age分组,并且把分组按照Age排序,然后取出前3条,最后再投影取得年龄,人数,平均工资。

// 获取Id>2的数据,然后按照Age分组,并且把分组按照Age排序,然后取出前3条,最后再投影取得年龄,人数,平均工资。
           var items= list.Where(e => e.Id > 2).GroupBy(g => g.Age).OrderBy(g => g.Key).Take(3).Select(g => new { NL = g.Key, RS = g.Count(), PJ = g.Average(e => e.Salary) });
            foreach(var i in items)
            {
                Console.WriteLine(i.NL+","+i.RS+","+i.PJ);
            }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值