Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-07-08 06:25:08

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

---

### 🧠 面试题:你真的理解闭包与循环变量吗?

#### 问题描述:

请看以下 C# 代码片段:

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

class Program
{
static void Main()
{
var actions = new Action[5];

for (var i = 0; i < 5; i++)
{
Task.Delay(10).ContinueWith(_ =>
{
Console.WriteLine(i);
});
}

Console.ReadLine();
}
}
```

#### 问题一:
这段代码输出的是什么?为什么?

#### 问题二(进阶):
如何修改上面的代码,使得每个 `ContinueWith` 输出的是它在循环中对应的索引值(即 0, 1, 2, 3, 4)?

#### 问题三(扩展):
如果将 `for` 循环改为 `Parallel.For`,会出现什么问题?如何确保线程安全并依然输出正确的索引值?

---

### ✅ 考察点解析:

- **闭包与变量捕获机制(Closure & Variable Capturing)**
- **异步编程模型中的上下文捕获**
- **循环变量生命周期的理解(C# 5.0 后的 for 循环行为变化)**
- **多线程/并行编程中的线程安全与变量共享问题**

---

### 💡 参考答案概要:

#### 回答一:
输出的可能是全部为 `5`(或不确定的值),因为 `i` 是被捕获的循环变量,在异步回调执行时,`i` 已经完成自增到 5。这是经典的“闭包捕获循环变量”陷阱。

#### 回答二:
应该在循环内部创建一个副本变量:

```csharp
for (var i = 0; i < 5; i++)
{
int copy = i;
Task.Delay(10).ContinueWith(_ =>
{
Console.WriteLine(copy);
});
}
```

或者使用 lambda 参数传入:

```csharp
Task.Delay(10).ContinueWith(_ => Console.WriteLine(i));
```

但注意:`ContinueWith` 中的 `_ => Console.WriteLine(i)` 仍会捕获 `i`,所以副本是必须的。

#### 回答三:
在 `Parallel.For` 中,多个线程并发执行,循环变量 `i` 的访问会存在竞争条件。应使用局部循环变量或将变量复制到每个线程的本地存储中,例如:

```csharp
Parallel.For(0, 5, i =>
{
int copy = i;
Task.Delay(10).ContinueWith(_ => Console.WriteLine(copy));
});
```

---

如果你能完整解释清楚这些问题,并写出线程安全且语义清晰的解决方案,说明你已经具备非常扎实的 C# 异步编程和语言机制理解能力!

需要我再出一道类似难度的题目吗?

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

上一篇: c#题例-2025-07-08 11:58:23

下一篇: c#题例-2025-07-08 00:51:48

精华推荐