Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-07-17 11:18:33

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

---

### 🧠 面试题:分析并解释以下代码的行为,并指出潜在问题

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

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

for (int i = 0; i < 10; i++)
{
Task.Delay(10).ContinueWith(_ =>
{
actions[i] = () => Console.WriteLine(i);
});
}

Task.Delay(1000).Wait(); // 等待所有 ContinueWith 执行完成

Parallel.For(0, 10, i =>
{
actions[i]?.Invoke();
});
}
}
```

---

### ❓问题:

1. **你预期输出是什么?**
2. **实际输出可能是什么?为什么?**
3. **这段代码存在哪些潜在的问题或 bug?**
4. **如何修改代码以确保输出符合预期(即每个 `Action` 输出的是它对应的索引值)?**

---

### 💡考察点解析:

| 考察内容 | 说明 |
|----------|------|
| **闭包捕获** | 在循环中使用 lambda 表达式捕获变量 `i`,需要注意是引用捕获还是值捕获。 |
| **异步编程模型(TPL)** | 使用了 `ContinueWith` 和 `Task.Delay`,需要理解任务调度和执行顺序。 |
| **线程安全问题** | 多个任务并发修改数组 `actions[i]`,存在写冲突风险。 |
| **Parallel.For 的行为** | 并行执行时调用 `actions[i]`,可能会读取尚未赋值的数组元素。 |
| **委托与延迟执行** | 委托中的 `Console.WriteLine(i)` 是在稍后调用时才执行的,此时 `i` 可能已变化。 |

---

### ✅参考答案(部分):

#### 1. 预期输出:
期望每个 `Action` 输出它在循环中对应的索引值,如:
```
0
1
2
...
9
```

#### 2. 实际输出:
由于 `i` 是在闭包中被捕获,不是在每次迭代中被复制,因此所有 `Action` 最终可能输出相同的值(比如全部是 `10` 或者中间某个值),因为循环早已结束。

此外,多个 `ContinueWith` 同时设置 `actions[i]`,也导致某些索引的 `Action` 没有被正确赋值。

#### 3. 存在的问题:
- 闭包捕获变量 `i` 引起的数据竞争。
- 对 `actions[i]` 的并发写入没有同步机制。
- 使用 `Parallel.For` 调用 `actions[i]` 时,无法保证所有任务已完成赋值。
- `ContinueWith` 默认使用当前任务调度器,可能导致执行顺序不可预测。

#### 4. 修改建议(一种方式):
```csharp
for (int i = 0; i < 10; i++)
{
int localCopy = i;
Task.Delay(10).ContinueWith(_ =>
{
actions[localCopy] = () => Console.WriteLine(localCopy);
});
}
```

或者使用更现代的方式重构为 `await` + `Task.Run` 来避免此类陷阱。

---

如果你需要更多类似难度级别的题目,我可以继续出一些关于 LINQ 表达式树、自定义 awaitable 类型、反射 emit IL、多线程死锁检测等方面的题目。是否需要?

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

上一篇: c#题例-2025-07-17 16:51:48

下一篇: c#题例-2025-07-17 04:31:59

精华推荐