找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3286

积分

0

好友

462

主题
发表于 昨天 03:11 | 查看: 0| 回复: 0

一、 先纠正一个常见误解

LINQ 不是:

  • 只是 Where / Select
  • 只是集合过滤工具
  • 只是“写得更短”

LINQ 本质是:

对「数据序列」的声明式查询模型

关键词只有 3 个:

  • 序列(Sequence)
  • 查询(Query)
  • 延迟(Lazy)

二、 什么是“序列”?

在 LINQ 眼里,下列东西本质一样

List<int>
int[]
ObservableCollection<User>
IEnumerable<Order>

👉 只要 实现了 IEnumerable<T> 👉 就是 “可枚举的序列”

LINQ ≠ 操作 List
LINQ = 操作「序列的流动」


三、 LINQ 解决了什么问题?

先看 没有 LINQ 的时代

var result = new List<int>();

foreach (var x in numbers)
{
if (x > 10)
    {
        result.Add(x * 2);
    }
}

问题不是“丑”,而是:

  • 关注点混杂(遍历 + 条件 + 处理)
  • 不可组合
  • 不可复用
  • 难表达“我想要什么”

四、 LINQ 的核心思想

用 LINQ 写的是:

var result = numbers
    .Where(x => x > 10)
    .Select(x => x * 2);

你描述的是:

*“我要一个:大于 10 的数 → 映射为 x2 的序列”**

而不是:

“怎么循环、什么时候加、存哪里”

👉 声明式,而不是命令式


五、 LINQ 的真正威力:可组合性

IEnumerable<int> Query(IEnumerable<int> source)
{
return source
        .Where(x => x > 10)
        .Select(x => x * 2)
        .OrderBy(x => x);
}
  • 不关心数据从哪来
  • 不关心最终用在哪
  • 可测试
  • 可复用
  • 可拼接

这正是 MVVM / 桌面架构极度需要的能力


Where 是“筛选数据”,还是“生成新的查询”?

👉 “筛选数据”

这是90% 初学者的第一直觉,但它是错误的认知模型

✅ 正确结论

Where 并没有筛选任何数据,它只是在「定义规则」

看这行代码:

var query = users.Where(u => u.Age >= 30);

此时发生了什么?

  • 没有遍历 users
  • 没有判断 Age
  • 没有产生任何结果

👉 Where 返回的是一个 新的 IEnumerable对象👉 这个对象里面 保存的是:

  • 数据源(users)
  • 规则(u => u.Age >= 30)

可以理解为:

query = “当你将来遍历我时,请用 users,
并且只返回 Age >= 30 的元素”

⚠️ Where = 生成一个查询对象,不是执行筛选

❷ 如果我从不枚举 result,LINQ 会不会真的执行?

只有“枚举行为”才会触发 LINQ 执行

❗ 什么叫「枚举行为」?

下面这些都会触发:

foreach (var x in query) { }   // ✅
query.ToList();                // ✅
query.ToArray();               // ✅
query.Count();                 // ✅
query.First();                 // ✅
string.Join(",", query);       // ✅(内部 foreach)

❸ “LINQ 为什么适合 ViewModel,不适合 UI 事件?”

❌ UI 事件里乱写 LINQ 会发生什么?

private void Button_Click(object sender, RoutedEventArgs e)
{
var result = users
        .Where(u => u.Age >= 30)
        .Select(u => u.Name)
        .ToList();

    ListBox.ItemsSource = result;
}

问题不是 LINQ 本身,而是:

  • ❌ 查询逻辑和 UI 耦合
  • ❌ 不能复用
  • ❌ 不能测试
  • ❌ 状态变化不可追踪
  • ❌ MVVM 被破坏

✅ ViewModel 里的 LINQ 是什么角色?

public IEnumerable<string> AdultUserNames =>
    Users.Where(u => u.Age >= 30)
         .Select(u => u.Name);

这里 LINQ 的作用是:

  • 描述数据关系
  • 声明业务规则
  • 自动响应数据变化
  • 不关心 UI

👉 LINQ 是 “数据变换语言”👉 ViewModel 正是 “数据变换层”

这就是它们天然匹配的原因


一、 IEnumerable 是什么

IEnumerable= “我能被一个一个地要元素”

源码级本质:

public interface IEnumerable<T>
{
IEnumerator<T> GetEnumerator();
}

👉 LINQ 操作的不是集合,而是“枚举过程”


二、 延迟执行(Lazy Execution)到底是什么意思?

看这段代码:

var query = users.Where(u => u.Age >= 30);

此时:

  • 没有遍历
  • 没有判断
  • 没有结果

只有当:

foreach (var u in query)

LINQ 才开始:

从 users 拿一个 → 判断 Age → 决定给不给你 → 再拿下一个

👉 一边要,一边算,一边返回


三、 为什么你后面加的数据会被算进去?

var query = users.Where(u => u.Age >= 30);

users.Add(new User { Name = "D", Age = 50 });

foreach (var u in query)
{
    Console.WriteLine(u.Name);
}

✅ 结果包含 D

原因只有一句话:

查询保存的是“规则 + 数据源引用”,不是结果


四、 什么时候 LINQ 会“冻结结果”?

var list = users
    .Where(u => u.Age >= 30)
    .ToList();

此时:

  • ✅ 立即执行
  • ✅ 数据被拷贝
  • ❌ 后续 users 变化不再影响 list

👉 ToList = 执行边界


练习 1

var query = users.Where(u => u.Age >= 30);
var list  = query.ToList();

users.Add(new User { Name = "E", Age = 60 });

👉 问:

  • query 再次枚举会不会有 E?
    会有,因为LINQ会被延迟执行,当枚举时,users中已经有E
  • list 会不会有 E?
    不会,因为list是利用query转换成的新的List

练习 2

var query = users
    .Where(u => {
        Console.WriteLine("checking " + u.Name);
return u.Age >= 30;
    });

👉 什么时候会打印? 👉 打印几次?

核心规则一句话给出:

Where 的 return 只决定“当前元素要不要给你”,而不是“结束查询”


枚举时的真实执行流程

假设 users 是:

A(20), B(35), C(40)

当你写:

foreach (var u in query)
{
    Console.WriteLine("use " + u.Name);
}

实际执行顺序是:

  1. checking A → return false → ❌ 不给你
  2. checking B → return true  → ✅ 给你 B
  3. checking C → return true  → ✅ 给你 C
  4. 枚举结束

👉 所有元素都会被 checking👉 return true ≠ 停止👉 return false ≠ 停止


❗ 什么情况下才会“遇到一个就停”?

只有这些操作才会 主动中断枚举

First()
FirstOrDefault()
Single()
Any()
Take(1)

对比示例

users
    .Where(u => {
        Console.WriteLine("checking " + u.Name);
return u.Age >= 30;
    })
    .First();

执行流程:

  1. checking A → false
  2. checking B → true → ✅ 立刻返回 → 停止枚举

👉 不是 Where 停的,是 First 停的


需要建立的心智模型

Where = 过滤器,不是查找器
return = 这个元素要不要通过
停止与否,由“下游算子”决定

这个代码会打印几次?

var query = users.Where(u =>
{
    Console.WriteLine("checking " + u.Name);
return u.Age >= 30;
});

foreach (var u in query) { }
foreach (var u in query) { }

打印两轮
原因一句话:

LINQ 查询默认是“可重复执行的规则”,不是结果缓存

理解 LINQ 的这种声明式与延迟执行的特性,是写出高效、可组合C#代码的关键。如果你想了解更多关于 LINQ 或其他 .NET 技术的深度解析与实践,可以到 云栈社区 的开发者论坛交流探讨。




上一篇:eBPF跟踪Shell/Python脚本的技术挑战与解决方案排查
下一篇:巨头转型复盘:Intel如何放弃内存红海,将命运押在80386 CPU上
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-6 06:09 , Processed in 0.288939 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表