c#题例-2025-06-29 13:52:27
日期: 2025-06-29 分类: AI写作 20次阅读
当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涉及到 **闭包、异步编程、捕获变量、线程安全和TPL(任务并行库)** 的综合理解:
---
### 🧠 面试题:深入理解异步闭包与变量捕获
#### 💬 题目描述:
你被要求分析以下 C# 代码,并回答两个问题:
```csharp
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
var tasks = new Task[10];
for (var i = 0; i < 10; i++)
{
tasks[i] = Task.Run(async () =>
{
await Task.Delay(100); // 模拟异步工作
Console.WriteLine(i);
});
}
await Task.WhenAll(tasks);
}
}
```
---
### ❓问题一:
这段代码的输出会是什么?为什么?
---
### ❓问题二:
如何修改这段代码,使其按预期顺序输出从 `0` 到 `9`?
---
### 🎯 参考答案要点:
#### ✅ 问题一解答:
输出可能是:
```
多个相同的值,比如全部是10 或者 不同但不连续的数字
```
**原因:**
- 这是因为在 `for` 循环中使用了循环变量 `i`,它被多个任务所捕获。
- 在 C# 5.0 及以后版本中,`for` 循环变量 `i` 是“循环体内部声明”的,因此在每次迭代中共享同一个变量。
- 所有闭包捕获的是同一个变量 `i`,而不是它的值副本。
- 当异步操作执行时,`i` 的值可能已经递增到 `10`,导致所有任务打印出的都是 `10`。
> ⚠️ 注意:如果你用的是 `foreach` 或者旧版本 C#(C# 5 之前),行为可能会不同。
---
#### ✅ 问题二解答:
要修复这个问题,需要确保每个任务都捕获一个**独立的变量副本**。可以通过在循环体内引入一个新的局部变量来实现:
```csharp
for (var i = 0; i < 10; i++)
{
int loopCopy = i; // 引入局部变量进行捕获
tasks[i] = Task.Run(async () =>
{
await Task.Delay(100);
Console.WriteLine(loopCopy);
});
}
```
这样,每次迭代都会创建一个新的 `loopCopy` 变量,闭包捕获的是这个新变量,保证了值的正确性。
---
### 🧩 深度扩展思考(可选追问):
- 如果不用 `Task.Run`,而是直接使用 `async/await` 创建任务,会发生什么?
- 如果将 `Console.WriteLine(i)` 改为调用某个同步方法,是否还存在变量捕获的问题?
- 如何在线程安全环境中处理类似问题?可以考虑使用 `ConcurrentBag
---
这道题能很好地考察候选人对 **异步编程模型、闭包、变量捕获机制、TPL 和线程调度** 的理解深度,非常适合用于高级或专家级 C# 开发者的面试。需要我再出一道类似的题目吗?
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐