C# LINQ查询表达式及对应LAMBDA表达式的用法
作者:hello黄先森 发布时间:2023-07-31 19:15:26
C#编程语言非常优美,我个人还是非常赞同的。特别是在学习一段时间C#后发现确实在它的语法和美观度来说确实要比其它编程语言强一些(也可能是由于VS编译器的加持)用起来非常舒服,而且对于C#我觉得他最优美之处不仅仅是语法糖方面还有就是体现在LINQ和Lambda表达式。
本篇文简单介绍一下关于C#当中LINQ表达式和其对应的Lambda表达式的用法,关于这两部分内容的相关参考资料:
人民邮电出版社《C#程序设计及应用教程》(第3版)
博客:《c# Linq查询》
同时在介绍的时候我会尽量挑出重要部分同时加上我自己的理解和认识,如有偏差还请指教。
首先先让我们看一下什么是LINQ查询表达式和Lambda表达式:
运行结果:
以上是对LINQ查询表达式和Lambda表达式的一个简单的应用,都是查询stu列表中年龄大于等于20岁的结果并且把结果按照年龄降序排列。
由此可见Linq表达式和Lambda表达式并没有什么可比性,只是用Lambda可以实现LINQ的查询语句。
那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在《深入理解C#》中称其为“点标记”。
例子中主要以LINQ表达式为主,LINQ表达式结构更为清晰易于理解,同时也会给出对应的点标记写法(所有的LINQ查询表达式都可以转成对应的点标记。反之,不是所有的点标记都可以转成查询表达式。),所以如果想要了解这部分的读者也请往下看。本文会介绍LINQ查询表达式用法以及对应的Lambda表达式。
LINQ查询表达式是一组查询技术的统称,其主要思想是将各种查询功能直接集成到C#语言中,不论是对象、XML、还是数据库都可以用LINQ编写查询语句。LINQ与传统迭代技术实现的查询优势在于更简明、更易读这种优势特别是在筛选多个条件时更为显著;使用很少的程序代码便能实现复杂的查询和筛选;无需修改或者是进行很少的修改就能移植到其它的数据源。LINQ查询语句并不复杂并且与SQL语句有些类似,学习起来难度并不大。
接下来直接看LINQ查询例子:
//以下为例子中涉及查询的数据
List<Student> stu = new List<Student>()
{
new Student(){Id = 1,Name = "王同学",Age = 24},
new Student(){Id = 2,Name = "王同学",Age = 30},
new Student(){Id = 3,Name = "王同学",Age = 21},
new Student(){Id = 4,Name = "赵同学",Age = 20},
new Student(){Id = 5,Name = "钱同学",Age = 22},
new Student(){Id = 6,Name = "孙同学",Age = 23},
new Student(){Id = 7,Name = "周同学",Age = 23},
new Student(){Id = 8,Name = "吴同学",Age = 20},
new Student(){Id = 9,Name = "郑同学",Age = 25},
new Student(){Id = 10,Name = "蒋同学",Age = 26}
};
查询年龄是30岁的王同学的信息:
//查询年龄是30岁的王同学的信息
var res = from t in stu
where t.Name == "王同学" && t.Age == 30
select t;
//对应的Lambda表达式
//var res1 = stu.Where(t => t.Age == 30 && t.Name == "王同学");
foreach (var item in res)//显示查询结果
{
Console.Write("学号:"+item.Id+"\n姓名:"+item.Name+"\n年龄:"+item.Age);
}
运行结果:
LINQ查询表达式必须以form子句开头,并且必须以select或group子句结尾。在第一个from子句和最后一个select或group子句之间,查询表达式可以包含一个或者多个where、orderby、join、let甚至附加from子句。LINQ表达式整体的用法和SQL语句很像,在上面的例子中就可以看出。
上面的例子的含义就是从数据源stu中查询一个数据“t”,“t”满足的条件就是它的Name是王同学同时它的Age是30,然后查询这个“t”。LINQ查询语句的返回值类型为IEnumerable<T>,LINQ执行查询时,一般利用foreach循环执行查询得到一个序列,这这种方式称为“延迟执行”。
什么是“延迟执行”?还是上面例子中的查询:
//查询年龄是30岁的王同学的信息
var res = from t in stu
where t.Name == "王同学" && t.Age == 30
select t;
//var res1 = stu.Where(t => t.Age == 30 && t.Name == "王同学");Lambda表达式写法
foreach (var item in res)
{
Console.Write("学号:"+item.Id+"\n姓名:"+item.Name+"\n年龄:"+item.Age);
}
Console.WriteLine("\n--------------------------------------------------------------------------");
stu.Add(new Student(){Id = 11,Name = "王同学",Age = 30});
foreach (var item in res)
{
Console.Write("学号:" + item.Id + "\n姓名:" + item.Name + "\n年龄:" + item.Age);
Console.WriteLine();
}
运行结果:
延迟查询就是只需构造一次查询语句,可以多次使用。在List中添加新元素之后并没有重新执行查询操作,然而res中的结果却根据List中元素的改变相应发生了改变。
从学生中选出年龄小于25岁并且按照年龄降序排列
//从学生中选出年龄小于25岁并且按照年龄降序排列
var res = from t in stu
where t.Age < 25
orderby t.Age descending
select t;
//var res1 = stu.Where(t => t.Age < 25).OrderByDescending(t => t.Age).Select(t => t);Lambda写法
foreach (var item in res)
{
Console.Write("学号:" + item.Id + "\n姓名:" + item.Name + "\n年龄:" + item.Age);
Console.WriteLine();
}
运行结果:
从学生中查询姓王的同学的信息并且按照年龄降序排列
//从学生中查询姓王的同学的信息并且按照年龄降序排列
var res = from t in stu
from n in t.Name
where n == '王'//名字中带有王字
orderby t.Age descending
select t;
//var res1 = stu.Where(t => t.Name.IndexOf("王") == 0).OrderByDescending(t => t.Age);lambda表达式
foreach (var item in res)
{
Console.Write("学号:" + item.Id + "\n姓名:" + item.Name + "\n年龄:" + item.Age);
Console.WriteLine();
}
运行结果:
学生信息按照年龄、Id进行排序
//参数越靠前,优先级越高
//先按age排序,当分数相同时再按id排序...依次类推
var res = from t in stu
orderby t.Age, t.Id
select t;
//var res1 = stu.OrderBy(t => t.Age).ThenBy(t => t.Id);Lambda表达式
foreach (var item in res)
{
Console.Write("学号:" + item.Id + "\n姓名:" + item.Name + "\n年龄:" + item.Age);
Console.WriteLine();
}
运行结果:
按照年龄进行分组,查询相同年龄数量大于2的内容
//按照年龄进行分组,查询相同年龄数量大于2的内容
var res = from t in stu
group t by t.Age into s
where s.Count()>=2
select s;
//var res1 = stu.GroupBy(t => t.Age).Where(s => s.Count() >= 2);lambda表达式
foreach (var item in res)
{
foreach (var items in item)
{
Console.Write("学号:" + items.Id + "\n姓名:" + items.Name + "\n年龄:" + items.Age);
Console.WriteLine();
}
Console.WriteLine();
}
运行结果:
查询出集合qSt中year等于集合qSc中year的元素并形成新的集合
List<s> pSt = new List<s>();
pSt.Add(new s() { year = 1999, name = "小张" });
pSt.Add(new s() { year = 2000, name = "小王" });
pSt.Add(new s() { year = 2001, name = "小李" });
pSt.Add(new s() { year = 2010, name = "小赵" });
List<school> pSc = new List<school>();
pSc.Add(new school() { year = 1999, name = "aaa" });
pSc.Add(new school() { year = 2001, name = "bbb" });
pSc.Add(new school() { year = 2002, name = "ccc" });
pSc.Add(new school() { year = 2010, name = "ddd" });
pSc.Add(new school() { year = 2012, name = "fff" });
var res = from t1 in pSc
from t2 in pSt
where t1.year == t2.year
select new {year = t1.year, name = t1.name + t2.name};
foreach (var item in res)
{
Console.Write("年:" + item.year + "姓名:" + item.name);
Console.WriteLine();
}
运行结果:
并行linq
并行查询可以分解查询的工作,使其分布在多个线程上。当pc拥有多个cpu时,可以看到并行查询带来的改进效果。并行LINQ适用于大型的集合查询,并拥有一定的优势。使用System.Collections.Concurrent.Partitioner.Create可以手动创建分区器。可以粗鲁的认为并行linq对于大集合的查询是优势比较明显的。取消长时间运行的并行linq查询可以设置利用System.Threading.CancellationTokenSource设置取消操作。
Console.WriteLine("开始构造大数组...");
//构造大数组
const int count = 100000000;
var data = new int[count];
var r = new Random();
for (int i = 0; i < count; i++)
{
data[i] = r.Next(40);
}
Console.WriteLine("开始计算...");
var st = System.DateTime.Now;
var sum = (from x in data where x > 20 select x).Sum();//常规linq-耗时1.8641s
var st2 = System.DateTime.Now;
var sum2 = (from x2 in data.AsParallel() where x2 > 20 select x2).Sum();//并行查询-耗时0.6620s
//var sum3 = data.AsParallel().Where(x3 => x3 > 20).Sum();//或并行查询----x3 => x3 > 20(Lambda表达式)
var st3 = System.DateTime.Now;
/*Partitioner.Create
手动创建分区器以及终止LINQ查询的方法可以详见文初的博客链接
Create具有多个重载,可依据需求进行分区*/
var sum4 = (from c in System.Collections.Concurrent.Partitioner.Create(data, true).AsParallel() where c > 20 select c).Sum();
var dt1 = st2 - st;
var dt2 = st3 - st2;
Console.WriteLine("常规linq耗时:{0}s", dt1.TotalSeconds.ToString());
Console.WriteLine("并行linq耗时:{0}s", dt2.TotalSeconds.ToString());
Console.ReadKey();
运行结果:
写在最后,如果你对以上LINQ以及对应的Lambda的使用方法都已经了解那你已经初步了解了LINQ查询表达式和Lambda表达式,这里需要说明的一点是关于Lambda的使用方法并不仅仅只限于进行查询,他是一个主要用于简化委托的代码编写形式,他用法远比文中介绍的更加广泛,本文是为了对比展现LINQ和Lambda。
来源:https://www.cnblogs.com/hellohxs/p/12266856.html


猜你喜欢
- 在网站开发中经常遇到级联数据的展示,比如选择城市的时候弹出的省市县选择界面。很多前端制作人员习惯于从JSON中而不是从数据库中获
- 1、问题引入我们已经完成了后台系统的登录功能开发,但是目前还存在一个问题,就是用户如果不登录,直接访问系统首页面,照样可以正常访问。很明显,
- 引言使用微信时我们会发现,首次进入微信的好友列表时,会加载好友头像,但是再次进入时,就不用重新加载了,而且其他页面都不用重新加载,说明微信的
- 一、简介CyclicBarrier 字面意思回环栅栏(循环屏障),它可以实现让一组线程等待至某个状态(屏障点)之后再全部同时执行。叫做回环是
- 在我们深入探讨C#序列化和反序列化之前我们先要明白什么是序列化,它又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。序列化就
- 本文实例为大家分享了java GUI学生图书管理的具体代码,供大家参考,具体内容如下- mysql数据库建表:1.book表 2.bs借书记
- 最近做了关于在Android设备上外接扫码的项目,在此记录一下关于Android USB扫码枪获取内容的问题首先我这边使用是USB HID的
- 本文实例讲述了Android编程之Sdcard相关代码。分享给大家供大家参考,具体如下:1. 检测Sdcard是否可用:public sta
- 目录一、导入依赖二、前端实现三、后台逻辑三、页面效果四、可能会遇到的问题一、导入依赖这里还是用了Apache的POI插件,现在一般的spri
- java实现字符串匹配暴力匹配/** * 暴力匹配 * * @param str1 需要找的总字符串 * @param str2 需要找到的
- 引言最近在工作中结合线程池使用 InheritableThreadLocal 出现了获取线程变量“错误&rdqu
- mybatis自动生成实体类、mapper文件、mapper.xml文件若采用mybatis框架,数据库新建表,手动编写的话,需要编写大量的
- java arrayList遍历的四种方法及Java中ArrayList类的用法package com.test;import java.u
- 前言Lifecycle是Jetpack架构组件中用来感知生命周期的组件,使用Lifecycles可以帮助我们写出和生命周期相关更简洁更易维护
- Android Studio常用快捷键、Android Studio快捷键大全接下来这篇android studio使用教程,主要为大家介绍
- 快速排序类using System;using System.Data;using System.Config
- 前言最近在看王清培前辈的.NET框架设计时,当中有提到扩展方法 .开头的一句话是:扩展方法是让我们在不改变类原有代码的情况下动态地添加方法的
- 一、java方法重写方法的重写是子类根据需求对父类继承的方法进行重新的编写,在重写时,可以使用super方法的方式来保留父类中的方法,注意:
- 什么是树?简单认识树 在生活中,有杨树,石榴树,枣树,而在计算机中的树呢,是一种非线性结构,是由 n(n>=0) 个有限节点
- 前提:微信公众平台:注册微信认证的公众号也就是服务号 ,拥有跟高级权限的微信接口。(注册服务号需要一些企业信息,需自己或者公司解决)注: 2