Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-07-13 07:58:37

当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涉及 **闭包、委托、异步编程、捕获变量和线程安全**等多个高级知识点:

---

### 🧠 面试题:闭包陷阱与异步执行顺序

```csharp
using System;
using System.Threading.Tasks;

class Program
{
static async Task Main(string[] args)
{
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` 的顺序?

---

### 💡考查点:

1. **变量捕获陷阱(Closure over loop variable)**
- 在 C# 中,`for` 循环中的 `i` 是被多个委托共享的,而不是每次迭代都创建一个新的副本。
- 因此,所有任务最终可能打印的是 `i` 最终的值(即 10),而不是各自迭代时的当前值。

2. **异步执行顺序**
- 所有任务都在异步等待,因此主线程不会立即执行 `Console.WriteLine(i)`,而是继续循环直到 `i == 10`。

3. **多线程访问共享变量的线程安全问题**
- 多个线程访问同一个变量 `i`,而它在循环结束后已经被改变。

4. **解决方案技巧**
- 如何正确地“固定”当前迭代的值,以供每个任务使用。

---

### ✅参考答案:

#### 输出结果:
```
10
10
10
...
10
```
(共输出十次 10)

#### 原因:
因为 `i` 是一个**循环变量**,它在整个循环中是同一个变量。所有的 lambda 表达式都引用了这个变量,而不是它的某个快照。当异步方法真正执行到 `Console.WriteLine(i)` 时,循环早已完成,此时 `i == 10`。

#### 正确写法(推荐方式):

```csharp
for (var i = 0; i < 10; i++)
{
int local = i; // 创建局部副本,确保每次迭代都有新的变量
tasks[i] = Task.Run(async () =>
{
await Task.Delay(100);
Console.WriteLine(local);
});
}
```

或者(不推荐,但也能工作):

```csharp
for (int i = 0; i < 10; i++)
{
int capture = i;
tasks[i] = Task.Run(async () =>
{
await Task.Delay(100);
Console.WriteLine(capture);
});
}
```

> ⚠️ 注意:从 C# 5 开始,在 `foreach` 循环中这个问题已被修复,但在 `for` 循环中仍然存在。

---

### 🧩拓展追问(进阶):

- 如果你将 `Task.Run` 替换为 `Task.Factory.StartNew(() => ..., TaskCreationOptions.LongRunning)`,是否会影响行为?
- 如果你想保证输出顺序是 `0 ~ 9` 并且按顺序打印,应如何处理?
- 如果你在 `Parallel.For` 中进行类似操作,该如何避免闭包陷阱?

---

如果你需要更多这类题目(比如 LINQ 表达式树、泛型约束、反射 emit、GC 根分析等),我也可以继续出。

除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: c#题例-2025-07-13 13:31:54

下一篇: c#题例-2025-07-13 02:25:15

精华推荐