c#题例-2025-07-17 04:31:59
日期: 2025-07-17 分类: AI写作 113次阅读
当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涉及到 **委托、泛型、闭包、线程安全和延迟执行**等多个高级概念:
---
### 🧠 面试题:理解委托链与闭包捕获
#### 问题描述:
请看以下代码片段:
```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
    static void Main()
    {
        var actions = new List
        for (int i = 0; i < 5; i++)
        {
            Task.Delay(10).Wait(); // 模拟异步操作,不影响逻辑
            int captured = i;
            actions.Add(() =>
            {
                Console.WriteLine($"i: {i}, captured: {captured}");
            });
        }
        Parallel.Invoke(actions.ToArray());
    }
}
```
#### 问题如下:
1. **输出结果是什么?为什么?**
2. 如果将 `int captured = i;` 改为 `var captured = i;` 是否会影响结果?为什么?
3. 如何修改该代码以确保每个 `Action` 输出的是循环当时的 `i` 值(即 0 到 4)?
4. 如果使用 `Task.Run` 替代 `Parallel.Invoke`,会出现什么潜在问题?如何解决?
---
### 💡 考察点解析:
| 考察点 | 解析 |
|--------|------|
| 闭包捕获 | 使用 lambda 表达式时对外部变量的捕获机制 |
| 变量捕获陷阱 | 在循环中直接捕获循环变量 `i` 会导致所有委托看到的是最终值 |
| 值类型 vs 引用类型 | 捕获 `int` 是值类型,但闭包会提升为类字段,导致共享状态 |
| 并行执行 | `Parallel.Invoke` 会并发执行委托,涉及线程调度和输出顺序不确定 |
| 泛型委托 | Action 的使用方式及其生命周期管理 |
---
### ✅ 参考答案简要:
1. **输出可能类似:**
   ```
   i: 5, captured: 0
   i: 5, captured: 1
   i: 5, captured: 2
   i: 5, captured: 3
   i: 5, captured: 4
   ```
   - 因为 `i` 是在闭包中被捕获的,而不是在每次迭代中复制。当委托执行时,`i` 已经变成 5。
   - `captured` 是每次迭代定义的新变量,因此正确保存了当时的值。
2. **`var captured = i;` 不影响结果。**  
   因为 `var` 只是类型推断,底层仍是 `int captured = i;`。
3. **修复方法:**
   ```csharp
   for (int i = 0; i < 5; i++)
   {
       int captured = i;
       actions.Add(() => Console.WriteLine($"captured: {captured}"));
   }
   ```
   或者使用局部函数/创建新作用域。
4. **使用 `Task.Run` 的问题:**
   - 多个任务并行执行时,`Console.WriteLine` 是线程安全的,但输出可能会交错。
   - 更严重的是,如果在 WinForm/WPF 中未捕获异常或未等待任务完成,可能导致程序提前退出。
---
如果你需要更偏向“设计模式”、“反射”或“性能优化”的专家级题目,也可以告诉我,我可以继续出一道 😄
 除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐

