CSDN博客链接:
https://blog.csdn.net/weixin_44293426/article/details/136058129?spm=1001.2014.3001.5501
语言集成查询(英语:Language Integrated Query,缩写:LINQ),
发音"link",是微软的一项技术,新增一种自然查询的SQL语法到.NET Framework的编程语言中,
当前可支持C#以及Visual Basic .NET语言。
2007年11月19日随.NET Framework 3.5发布了LINQ技术。
包括LINQ to Objects、LINQ to SQL、LINQ to Datasets、LINQ to Entities、LINQ to Data Source、LINQ to XML/XSD等
-
查询表达式是一种使用查询语法表示的表达式,它用于查询和转换来自任意支持LINQ的数据源中的数据。
-
查询表达式使用常见的C#语言构造,易读简洁,容易掌握。
-
它由一组类似于SQL或XQuery的声明性语法编写的子句组成。
-
每一个子句可以包含一个或多个C#表达式,这些C#表达式本身也可能是查询表达式或包含查询表达式。
查询表达式必须以
from
子句开头,以
select
或
group
子句结束。在第一个
from
子句和最后一个
select
子句或
group
子句之间,可以包含一个或多个
where
子句、
let
子句、
join
子句、
orderby
子句和
group
子句,甚至还可以是
from
子句。
from
子句指定的数据源类型必须为
IEnumerable
、
IEnumerable<>
或一种派生类型
它包括8个基本子句,具体说明如下所示。
-
from子句
指定查询操作的数据源和范围变量。
-
select子句
指定查询结果的类型和表现形式。
-
where子句
指定筛选元素的逻辑条件。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine("\t-- Linq --");
var res = from m in list
where m % 2 == 0
select m;
foreach (var r in res)
Console.WriteLine(r);
Console.WriteLine("\t-- Lambda --");
var res1 = list.FindAll(m => m % 2 == 0);
foreach (var r in res1)
Console.WriteLine(r);
Console.ReadKey();
- let子句
引入用来临时保存查询表达式中的子表达式结果的范围变量。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine("\t-- Linq --");
var res = from m in list
let isFlag = m % 2 == 0 // from m in list
where isFlag // where m % 2 == 0
select m; // select m;
foreach (var r in res)
Console.WriteLine(r);
Console.WriteLine("\t-- Lambda --");
var res1 = list.FindAll(m => m % 2 == 0);
foreach (var r in res1)
Console.WriteLine(r);
Console.ReadKey();
输出结果同上
- orderby子句
对查询结果进行排序操作,包括升序和降序。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine("\t-- Linq --");
//var res = from m in list
// where 1 < m && m < 6
// orderby m descending // 降序
// select m;
var res = from m in list
where 1 < m && m < 6
orderby m ascending // 升序
select m;
foreach (var r in res)
Console.WriteLine(r);
Console.WriteLine("\t-- Lambda --");
//var res1 = list.Where(m => 1 < m && m < 6).OrderByDescending(m => m); // 降序
var res1 = list.Where(m => 1 < m && m < 6).OrderBy(m => m); // 升序
foreach (var r in res1)
Console.WriteLine(r);
Console.ReadKey();
ascending可以省略不写,因为默认是升序排列
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine("\t-- Linq --");
var res = from m in list
where 1 < m && m < 6
orderby m % 2, m descending // 先按照 m % 2 升序排序, 再按照 m 降序排序
select m;
foreach (var r in res)
Console.WriteLine(r);
Console.WriteLine("\t-- Lambda --");
var res1 = list.Where(m => 1 < m && m < 6)
.OrderBy(m => m % 2)
.ThenByDescending(m => m);
foreach (var r in res1)
Console.WriteLine(r);
Console.ReadKey();
- group子句
对查询结果进行分组。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine("\t-- Linq --");
var res = from m in list
where 1 < m && m < 6
group m by m % 2;
foreach (var r in res)
Console.WriteLine("Key: " + r.Key);
foreach (var s in r)
Console.Write("Value: " + s + "\t");
Console.WriteLine();
Console.WriteLine("\t-- Lambda --");
var res1 = list.Where(m => 1 < m && m < 6)
.GroupBy(m => m % 2);
foreach (var r in res1)
Console.WriteLine("Type: " + r);
foreach (var r in res1)
Console.WriteLine("Key: " + r.Key);
foreach (var s in r)
Console.Write("Value: " + s + "\t");
Console.WriteLine();
Console.ReadKey();
- into子句
提供一个临时标识符。join子句、group子句或select子句可以通过该标识符引用查询操作中的中间结果。
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Console.WriteLine("\t-- Linq --");
var res = from m in list
where 1 < m && m < 6
group m by m % 2 into tmp
from t in tmp
where t > 3
select t;
foreach (var r in res)
Console.WriteLine(r);
Console.WriteLine("\t-- Lambda --");
var res1 = list.Where(m => 1 < m && m < 6)
.GroupBy(m => m % 2)
.SelectMany(m => m)
.Where(m => m > 3);
foreach (var r in res1)
Console.WriteLine(r);
Console.ReadKey();
- join子句
连接多个用于查询操作的数据源。
8.1 内部联接(inner join – join on)
元素的联接关系必须同时满足两个数据源,类似于SQL语句中的inner join子句
join子句的内部联接要求两个数据源必须存在相同的值,即两个数据源都必须存在满足联接关系的元素
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list1 = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> list2 = new List<int>() { 0, 2, 4, 6, 8 };
Console.WriteLine("\t-- Linq --");
var res1 = from m in list1
where 1 < m && m < 6
join n in list2 on m equals n
select m;
foreach (var r in res1)
Console.WriteLine(r);
Console.WriteLine("\t-- Lambda --");
var res2 = list1.Where(m => 1 < m && m < 6)
.Join(list2, m => m, n => n, (m, n) => m);
foreach (var r in res2)
Console.WriteLine(r);
Console.ReadKey();
8.2 分组联接(group join – join on into)
包含into子句的join子句
将左数据源与右数据源的元素依次匹配。
左数据源的所有元素都出现在查询结果中。
若在右数据源中找到匹配项,则使用匹配的数据,否则用空表示
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list1 = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> list2 = new List<int>() { 0, 2, 4, 6, 8 };
Console.WriteLine("\t-- Linq --");
var res1 = from m in list1
where 1 < m && m < 6
join n in list2 on m equals n into g
select new
ID = m,
Values = g
foreach (var r in res1)
Console.WriteLine("type: " + r);
Console.WriteLine("Key: " + r.ID);
foreach (var s in r.Values)
Console.Write("Value: " + s + "\t");
Console.WriteLine();
Console.WriteLine("\t-- Lambda --");
var res2 = list1.Where(m => 1 < m && m < 6)
.GroupJoin(list2, m => m, n => n, (m, g) => new { ID = m, Values = g });
foreach (var r in res2)
Console.WriteLine("Key: " + r.ID);
foreach (var s in r.Values)
Console.Write("Value: " + s + "\t");
Console.WriteLine();
Console.ReadKey();
8.3 左外部联接(left outer join – join on into default)
元素的联接关系必须满足联接中的左数据源,类似于SQL语句中的left join子句
join子句的左外部联接将返回左侧数据源序列中的所有元素,就算他们在右侧序列中没有匹配的元素也是这样
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
List<int> list1 = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> list2 = new List<int>() { 0, 2, 4, 6, 8 };
Console.WriteLine("\t-- Linq --");
var res1 = from m in list1
where 1 < m && m < 6
join n in list2 on m equals n into g
// 如果序列为空, 则DefaultIfEmpty()方法返回只包含一个元素的序列, 该元素类型的值为默认值(在此为0)
from ab in g.DefaultIfEmpty()
select ab;
foreach (var r in res1)
Console.Write(r + "\t");
Console.WriteLine("\n\t-- Lambda --");
var res2 = list1.Where(m => 1 < m && m < 6)
.GroupJoin(list2, m => m, n => n, (m, g) => g.DefaultIfEmpty());
foreach (var r in res2)
Console.WriteLine("type: " + r);
foreach (var s in r)
Console.Write(s + "\t");
Console.WriteLine();
Console.ReadKey();
不难发现,这三种联接要求的严格程度是越来越低的
内部联接最高,只获取满足条件的
分组联接次之,不满足条件返回空
左外部联接最宽容,不满足条件给默认值
Linq、Lambda表达式使用时机
在项目中使用 LINQ 或 Lambda 表达式的选择通常取决于项目的特定需求、团队的编码风格以及性能考虑等因素。
虽然 LINQ 和 Lambda 表达式都是 C# 中强大的功能,但它们各自有着不同的优缺点。
LINQ 语法:
可读性高:LINQ 语法更接近自然语言,更容易理解,特别是对于非专业程序员或者初学者来说。
可组合性强:LINQ 提供了丰富的查询操作符,可以方便地进行多个操作的组合,编写出简洁、清晰的查询语句。
与数据库查询类似:LINQ 语法与 SQL 查询语句相似,对于熟悉数据库的开发者来说更容易上手。
Lambda 表达式:
更灵活:Lambda 表达式可以实现更复杂的逻辑,可以直接嵌入到代码中,提高了代码的灵活性和可读性。
更适合链式调用:Lambda 表达式更适合于链式调用的场景,比如使用 Where、Select、OrderBy 等方法进行数据筛选和排序。
建议和注意事项:
团队编码风格:在团队中,建议统一选择一种风格,以保持代码的一致性和可维护性。
性能考虑:在性能要求高的场景下,Lambda 表达式通常比 LINQ 语法更高效,因为 Lambda 表达式通常可以通过委托直接调用方法,而 LINQ 语法可能会生成更多的中间代码。
项目需求:根据项目的需求和特点选择合适的编码方式。如果项目需要更直观的查询语法、更易于理解的代码,可以选择 LINQ 语法;如果需要更灵活、更高效的操作方式,可以选择 Lambda 表达式。
综上所述,虽然 LINQ 语法在可读性方面更优,但 Lambda 表达式更灵活、更适合链式调用,因此在项目中的选择取决于团队的实际需求和偏好。
在Enumerable类中还有很多方法支持Lambda写法,学无止境,加油!
using System;
using System.Linq;
namespace ConsoleApp2
internal class Program
static void Main(string[] args)
int[] arr = new int[] { 1, 2, 4, 5, 7, 8 };
// 创建一个查询表达式i, 查询arr数组中大于3的元素和10的乘积
var i = from e in arr where e > 3 select e * 10;
//var i = arr.Where(e => e > 3).Select(e => e * 10);
Console.WriteLine(“查询结果如下:”);
foreach (var a in i)
Console.Write(a + “\t”); // 打印输出结果
Console.WriteLine();
Console.ReadKey();