目录
LINQ是.NET Core中提供的简化数据查询的技术。使用该技术可以用几行代码就实现复杂的数据查询。
一、Lambda表达式
Lambda表达式是c#中的语法,他可以让我们进行函数式编程,减少代码量。
1.1.回顾委托
什么是委托?
委托是一种指向方法的类型。
委托的用法?
在.NET中最多定义16个参数的泛型委托Action(无返回值)和Func(有返回值),因此我们一般不用自定义委托,直接用Action或者Func这两个委托类型。
/*
* 委托指向普通方法
*/
MyDelegate d1 = SayEnglish;
string s1 = d1(3);
Console.WriteLine(s1);
d1 = sayChinese;
string s2 = d1(5);
Console.WriteLine(s2);
static string SayEnglish(int age)
{
return $"hello {age}";
}
static string sayChinese(int age)
{
return $"你好 {age}";
}
delegate string MyDelegate(int n);//定义委托
/*
* 委托指向匿名方法
*/
Func<int, int, string> f1 = delegate (int i, int j)//string是返回值类型
{
return $"{i}+{j}={i + j}";
};
String s = f1(1, 2);
Console.WriteLine(s);
1.2Lambda的使用
用Lambda表达式进行代码简化:
//去掉delegate关键字,省略了参数的数据类型
Func<int, int, string> f1 = (i,j) =>
{
return $"{i}+{j}={i + j}";
};
如果=>后的表达式只有一行代码,并且方法有返回值,那么也可以省略方法体的花括号以及return关键字。
Func<int, int, string> f1 = (i,j) => $"{i}+{j}={i + j}";
简述Lambda表达式的简化规则:
(1)如果一个方法没有返回值,并且方法体只有一行代码,那么方法体的花括号可以省略
Action<int ,string> a = (age,name) => Console.WriteLine($"年龄{age},姓名{name}");
(2)如果方法只有一个参数,那么Lambda表达式表达式的参数括号可以省略
Func<int ,int> j = i => i * 2;
二、常用集合类的扩展方法
LINQ关键功能是提供集合类的扩展方法,所有实现了IEnumerable<T>接口的类都可以用这些方法。这些方法不是IEnumerable<T>中的方法,而是以扩展方法的形式存在于System.Linq命名空间的静态类。
2.1Where的使用
Where方法是用于根据条件对数据进行过滤。
如何用Where获取工资高于2500元且年龄低于35岁的员工?
IEnumerable<Employee> list1 = list.Where(e => e.Salary > 2500 && e.Age < 35);
foreach (Employee e in list1)
{
Console.WriteLine(e);
}
Where方法是一个Lambda表达式格式的匿名方法,方法的参数e表示当前待判断的元素值。
2.2Count的使用
Cout方法用于获取数据条数。有两个重载方法:
(1)没有参数的方法(获取数据条数)
(2)Func<TSourse,bool> predicate类型参数(获取符合predicate条件的数据条数)
如何用获取工资高于5000元或者年龄低于30岁的员工?
int count1 = list.Count(e => e.Salary > 5000 || e.Age < 30);
int count2 = list.Where(e => e.Salary > 5000 || e.Age < 30).Count();
注意:如果过滤条件返回的数据条数太多,超过int的最大范围,那么可以调用返回值是long类型的LongCount方法,用法与Count一样。
2.3Any的使用
Any方法用于判断集合中是否至少有一条满足条件的数据。返回值为bool类型。
(1)没有参数的重载方法
(2)Func<TSourse,bool> predicate类型参数
如何判断是否存在工资高于8000元的员工?
bool b1 = list.Any(e => e.Salary > 8000);
bool b2 = list.Where(e => e.Salary > 8000).Any();
思考:其实是否利用Count也可以实现该功能?
答案是肯定的,但是Any的效率会高于Count,因为Any只要找到一个符合条件的就会停止查询,所以如果只想判断数据是否存在,就使用Any方法即可。
2.4获取一组数据的方法
在LINQ中有4组获取一条数据的方法,分别是Single、SingleOrDefault、First和FirstOrDefault方法。这四个方法的返回值都是符合条件的一条数据,每组方法也同样有两个重载方法。下面解释下四个方法的区别:
Single:有且只有一条数据满足要求使用该方法,没有或者多于一条就会抛异常
SingleOrDefault:最多一条满足要求的数据,没有返回类型默认值,多于一条就会抛异常
First:一条或者多条数据时返回第一条数据,没有数据则抛出异常
FirstOrDefault:一条或者多条数据时返回第一条数据,没有数据返回类型默认值
2.5排序方法
OrderBy方法可以对数据进行正向排序,OrderByDescending方法则对数据进行逆向排序。
2.6限制结果集
限制结果集用来从集合中获取部分数据,主要用于分页查询。
Skip(n):跳过n条数据。
Take(n):获取n条数据。
2.7聚合函数
在LINQ中也有聚合函数,比如Max(最大值),Min(最小值),Average(平均值),Sum(总和),Count(总数)。
2.8分组 (GroupBy)
如何根据年龄分组,然后计算组内人数,平均工资?
/*
* IGrouping是一个继承于IEnumerable的接口
* GruopBy的返回值是IGrouping<int, Employee>类型的泛型IEnumerable
* Key这一属性是IGrouping唯一的成员
*/
IEnumerable<IGrouping<int, Employee>> items = list.GroupBy(e => e.Age);
foreach(IGrouping<int, Employee> item in items)
{
int age=item.Key;
int count = item.Count();
int maxSalary = item.Max(e => e.Salary);
double avgSalary=item.Average(e => e.Salary);
Console.WriteLine($"年龄{item.Key},人数{count},最高工资{maxSalary},平均工资{avgSalary}");
}
在使用LINQ相关代码时可以考虑多使用var关键,它可以省去书写复杂变量类型的过程。编译器会根据变量上下文环境推测变量类型。
2.9投影(Select)
Select方法用于把集合中的每一项逐项转换为另一种类型。
Select方法中使用匿名类型
2.10集合转换
集合操作大部分都是IEnumerable<T>类型,但是有些地方需要用数组类型或者List<T>类型的变量,我们可以用ToArray和ToList方法进行转换。
Employee[] items1 = list.Where(e => e.Salary > 3000).ToArray();
List<Employee> items2 = list.Where(e => e.Salary > 3000).ToList();
三、LINQ扩展方法之链式调用
如何完成“获取Id>2的数据,再按照Age分组,再将分组按照Age排序,然后取出前3条,最后投影取得年龄、人数、平均工资”?
LINQ的技术就分析就到此吧,不知道大家有没有感受到Csharp语法的优美呢?