c#题例-2025-07-21 13:25:18
日期: 2025-07-21 分类: AI写作 15次阅读
当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涉及 **多线程、异步编程、线程安全、闭包陷阱** 和 **任务调度顺序** 等多个高级知识点:
---
### 🧠 面试题:理解 async/await、Task、闭包和线程池调度
#### 💬 题目描述:
阅读以下 C# 控制台程序代码,预测并解释其**输出结果**,并说明为什么会出现这样的输出。
```csharp
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
int capturedVariable = 0;
for (int i = 0; i < 5; i++)
{
int loopVariable = i;
capturedVariable = i * 10;
Task.Run(async () =>
{
await Task.Delay(100); // 模拟异步工作
Console.WriteLine($"loopVariable = {loopVariable}, capturedVariable = {capturedVariable}");
});
}
await Task.Delay(1000); // 等待所有任务完成
}
}
```
---
### 🧾 面试要求:
1. **预测输出结果**(假设线程调度是随机的,但输出格式保持一致)。
2. 解释:
- 为什么 `loopVariable` 的值是确定的?
- 为什么 `capturedVariable` 的值可能不是你期望的?
- 这个问题涉及到哪些 C# 中的闭包、捕获变量、异步编程相关的陷阱?
3. 如何修改代码以确保 `capturedVariable` 的值与当前循环迭代一致?
---
### ✅ 参考答案(供面试官参考):
#### 🔍 输出结果(可能):
```
loopVariable = 0, capturedVariable = 40
loopVariable = 1, capturedVariable = 40
loopVariable = 2, capturedVariable = 40
loopVariable = 3, capturedVariable = 40
loopVariable = 4, capturedVariable = 40
```
> 注意:`loopVariable` 的值是确定的,而 `capturedVariable` 的值是最终循环结束后最后一次赋值的值(即 40)。
---
### 📚 关键知识点解析:
#### 1. **闭包中的变量捕获陷阱(loopVariable vs capturedVariable)**
- `loopVariable` 是在每次循环中声明的局部变量,每次循环都会创建一个新的变量实例。
- 因此,lambda 表达式捕获的是**当前循环中具体的一个 loopVariable 实例**。
- `capturedVariable` 是在循环外声明的变量,每次循环都只是重新赋值。
- 所有任务捕获的是**同一个变量引用**,当任务真正执行时,循环早已结束,`capturedVariable` 的值已经是 40。
#### 2. **异步执行延迟导致的副作用**
- 所有任务都是异步延迟执行(`await Task.Delay(100)`),而主线程继续执行循环直到结束。
- 因此,在任务执行时读取的 `capturedVariable` 已经被循环修改为最终值。
#### 3. **如何修复?**
要确保每个任务捕获的是当前循环迭代的值,可以这样做:
```csharp
int capturedVariableSnapshot = capturedVariable;
int loopVariableSnapshot = loopVariable;
Task.Run(async () =>
{
await Task.Delay(100);
Console.WriteLine($"loopVariable = {loopVariableSnapshot}, capturedVariable = {capturedVariableSnapshot}");
});
```
或者将变量复制到循环内部:
```csharp
for (int i = 0; i < 5; i++)
{
int loopVariable = i;
int capturedVariable = i * 10; // 在循环内定义,避免共享
Task.Run(async () =>
{
await Task.Delay(100);
Console.WriteLine($"loopVariable = {loopVariable}, capturedVariable = {capturedVariable}");
});
}
```
---
### 🧩 延伸问题(用于考察深度):
- 如果将 `Task.Run` 替换为 `Task.Factory.StartNew`,是否会有不同?
- 如果不使用 `await Task.Delay(100)`,而是同步调用 `Thread.Sleep(100)`,输出是否改变?
- 使用 `ValueTask` 替代 `Task` 是否会影响行为?
- 如何使用 `ConcurrentDictionary` 或其他线程安全结构避免变量捕获问题?
---
如果你需要更多类似级别的题目(比如涉及表达式树、反射、LINQ 优化、TPL 数据流块、内存模型、volatile 等),我也可以继续出题。
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐