404 Not Found

404 Not Found


nginx

LINQ查询

LINQ概念与动机

LINQ(Language Integrated Query)是C#中内置的数据查询语言,允许用统一的语法查询不同数据源(集合、数据库、XML等)。在没有LINQ之前,查询不同数据源需要学习不同的API,LINQ解决了这一问题。

示例

CSHARP
using System;
using System.Linq;

int[] numbers = { 5, 12, 3, 21, 8, 15 };

var result = from n in numbers
             where n > 10
             select n;

foreach (var n in result)
{
    Console.WriteLine(n);
}
▶ 试一试
TEXT
12
21
15

查询语法与方法语法

LINQ提供两种写法:查询语法(Query Syntax)和方法语法(Method Syntax)。两者功能等价,方法语法在实际开发中更常用,因为支持更多操作符且链式调用更简洁。

示例

CSHARP
using System;
using System.Linq;

int[] numbers = { 5, 12, 3, 21, 8, 15 };

var querySyntax = from n in numbers
                  where n > 10
                  orderby n
                  select n;

var methodSyntax = numbers.Where(n => n > 10).OrderBy(n => n);

Console.WriteLine("查询语法: " + string.Join(", ", querySyntax));
Console.WriteLine("方法语法: " + string.Join(", ", methodSyntax));
▶ 试一试
TEXT
查询语法: 12, 15, 21
方法语法: 12, 15, 21

from / where / select / orderby / group

查询语法核心子句:from指定数据源和范围变量,where过滤,select投影结果,orderby排序,group ... by分组。

示例

CSHARP
using System;
using System.Linq;

string[] names = { "Alice", "Bob", "Anna", "Charlie", "Amy" };

var result = from name in names
             where name.StartsWith("A")
             orderby name.Length
             select name;

foreach (var name in result)
{
    Console.WriteLine(name);
}
▶ 试一试
TEXT
Amy
Anna
Alice

group by 分组示例

CSHARP
using System;
using System.Linq;

var students = new[]
{
    new { Name = "张三", Grade = "A" },
    new { Name = "李四", Grade = "B" },
    new { Name = "王五", Grade = "A" },
    new { Name = "赵六", Grade = "C" },
    new { Name = "孙七", Grade = "B" }
};

var groups = from s in students
             group s by s.Grade into g
             select new { Grade = g.Key, Count = g.Count() };

foreach (var g in groups)
{
    Console.WriteLine($"等级 {g.Grade}: {g.Count} 人");
}
TEXT
等级 A: 2 人
等级 B: 2 人
等级 C: 1 人

常用操作符

方法语法下常用的LINQ操作符如下:

操作符 用途
Where 过滤元素
Select 投影转换
OrderBy / OrderByDescending 升序/降序排序
ThenBy 二级排序
GroupBy 分组
First / FirstOrDefault 取第一个元素
Single / SingleOrDefault 取唯一元素
Count 计数
Any 是否存在元素
All 是否全部满足条件
Sum / Average 求和/平均值
Min / Max 最小值/最大值
Skip / Take 跳过/取指定数量
Distinct 去重
ToList / ToArray / ToDictionary 转换为集合

示例

CSHARP
using System;
using System.Linq;

int[] numbers = { 3, 7, 2, 9, 5, 7, 3, 8 };

Console.WriteLine("Where > 5: " + string.Join(", ", numbers.Where(n => n > 5)));
Console.WriteLine("Select x2: " + string.Join(", ", numbers.Select(n => n * 2)));
Console.WriteLine("OrderBy: " + string.Join(", ", numbers.OrderBy(n => n)));
Console.WriteLine("OrderByDescending: " + string.Join(", ", numbers.OrderByDescending(n => n)));
Console.WriteLine("Distinct: " + string.Join(", ", numbers.Distinct()));
Console.WriteLine("First: " + numbers.First());
Console.WriteLine("FirstOrDefault > 10: " + numbers.FirstOrDefault(n => n > 10));
Console.WriteLine("Count > 5: " + numbers.Count(n => n > 5));
Console.WriteLine("Any > 8: " + numbers.Any(n => n > 8));
Console.WriteLine("All > 1: " + numbers.All(n => n > 1));
Console.WriteLine("Sum: " + numbers.Sum());
Console.WriteLine("Average: " + numbers.Average());
Console.WriteLine("Min: " + numbers.Min());
Console.WriteLine("Max: " + numbers.Max());
Console.WriteLine("Skip 3 Take 2: " + string.Join(", ", numbers.Skip(3).Take(2)));
▶ 试一试
TEXT
Where > 5: 7, 9, 7, 8
Select x2: 6, 14, 4, 18, 10, 14, 6, 16
OrderBy: 2, 3, 3, 5, 7, 7, 8, 9
OrderByDescending: 9, 8, 7, 7, 5, 3, 3, 2
Distinct: 3, 7, 2, 9, 5, 8
First: 3
FirstOrDefault > 10: 0
Count > 5: 4
Any > 8: True
All > 1: True
Sum: 44
Average: 5.5
Min: 2
Max: 9
Skip 3 Take 2: 9, 5

LINQ与List和Array

LINQ可以作用于任何实现了IEnumerable<T>接口的对象,包括List<T>和数组T[]

示例

CSHARP
using System;
using System.Collections.Generic;
using System.Linq;

List<string> fruits = new List<string> { "apple", "banana", "cherry", "date" };

var longNames = fruits.Where(f => f.Length > 5).Select(f => f.ToUpper());
Console.WriteLine("List查询: " + string.Join(", ", longNames));

int[] scores = { 88, 72, 95, 60, 85 };
var topScores = scores.Where(s => s >= 85).OrderByDescending(s => s);
Console.WriteLine("Array查询: " + string.Join(", ", topScores));
▶ 试一试
TEXT
List查询: BANANA, CHERRY
Array查询: 95, 88, 85

LINQ与Dictionary

对字典使用LINQ时,每个元素是KeyValuePair<TKey, TValue>,通过.Key.Value访问键和值。

示例

CSHARP
using System;
using System.Collections.Generic;
using System.Linq;

var prices = new Dictionary<string, decimal>
{
    { "苹果", 5.5m },
    { "香蕉", 3.2m },
    { "橙子", 7.8m },
    { "葡萄", 12.0m }
};

var expensive = prices.Where(kv => kv.Value > 5m)
                      .OrderByDescending(kv => kv.Value)
                      .Select(kv => $"{kv.Key}: {kv.Value}元");

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

var priceDict = prices.ToDictionary(kv => kv.Key, kv => kv.Value * 2);
Console.WriteLine("翻倍后橙子价格: " + priceDict["橙子"]);
▶ 试一试
TEXT
葡萄: 12.0元
橙子: 7.8元
苹果: 5.5元
翻倍后橙子价格: 15.6

延迟执行与立即执行

LINQ查询默认是延迟执行的:定义查询时不会运行,只有在遍历结果(如foreach)时才真正执行。调用ToList()ToArray()Count()First()等方法会触发立即执行。

示例

CSHARP
using System;
using System.Collections.Generic;
using System.Linq;

var numbers = new List<int> { 1, 2, 3 };

var query = numbers.Where(n => n > 1);

numbers.Add(4);
numbers.Add(5);

Console.WriteLine("延迟执行结果包含后来添加的元素:");
foreach (var n in query)
{
    Console.WriteLine(n);
}

var immediate = numbers.Where(n => n > 1).ToList();

numbers.Add(6);

Console.WriteLine("立即执行结果不包含后来添加的6:");
foreach (var n in immediate)
{
    Console.WriteLine(n);
}
▶ 试一试
TEXT
延迟执行结果包含后来添加的元素:
2
3
4
5
立即执行结果不包含后来添加的6:
2
3
4
5

💡 延迟执行意味着每次遍历查询结果都会重新计算。如果需要多次使用结果,应调用ToList()缓存。

IQueryable与IEnumerable

IEnumerable<T>用于内存中的集合查询(LINQ to Objects),IQueryable<T>用于远程数据源查询(如数据库),它可以将表达式树翻译为SQL等查询语言在服务端执行。

示例

CSHARP
using System;
using System.Collections.Generic;
using System.Linq;

List<int> data = new List<int> { 10, 20, 30, 40, 50 };

IEnumerable<int> enumerableQuery = data.Where(n => n > 25);
IQueryable<int> queryableQuery = data.AsQueryable().Where(n => n > 25);

Console.WriteLine("IEnumerable结果: " + string.Join(", ", enumerableQuery));
Console.WriteLine("IQueryable结果: " + string.Join(", ", queryableQuery));
Console.WriteLine("IQueryable表达式: " + queryableQuery.Expression);
▶ 试一试
TEXT
IEnumerable结果: 30, 40, 50
IQueryable结果: 30, 40, 50
IQueryable表达式: System.Collections.Generic.List`1[System.Int32].Where(n => (n > 25))

⚠️ 使用EF Core等ORM时,IQueryable会在数据库端执行过滤,而IEnumerable会把数据全部加载到内存再过滤,性能差异巨大。

❓ 常见问题

Q 查询语法和方法语法哪个更好?
A 方法语法更常用,支持所有操作符且链式调用简洁;查询语法仅支持部分操作符,但对复杂join/group更易读。
Q FirstOrDefault和First有什么区别?
A First在无元素时抛异常,FirstOrDefault返回默认值(引用类型null,值类型0),推荐优先使用FirstOrDefault。
Q Single和First有什么区别?
A Single要求序列有且仅有一个匹配元素,多于一个也抛异常;First取第一个匹配元素即可。
Q 为什么遍历LINQ结果两次会执行两次查询?
A 因为延迟执行,每次遍历都重新计算。用ToList()缓存结果可避免重复计算。
Q IQueryable和IEnumerable如何选择?
A 查数据库用IQueryable让SQL在服务端执行;查内存集合用IEnumerable即可。

📖 小节

📝 作业

  1. 给定int[] nums = { 34, 7, 21, 56, 12, 89, 3 },用方法语法找出所有大于20的偶数并降序排列,输出结果
  2. 定义一个学生列表(姓名、年龄、班级),用LINQ按班级分组,输出每个班级的学生数量
  3. 创建一个Dictionary<string, int>存储商品名称和库存,用LINQ找出库存小于10的商品名称,并转换为List<string>
  4. 编写代码演示延迟执行:定义一个查询后修改原集合,观察遍历结果是否包含新元素;然后用ToList()对比立即执行的行为
  5. 解释IQueryable在EF Core中为什么比IEnumerable更高效,用一句话概括原因
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏