Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-08-02 15:25:20

当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涉及 **闭包、委托、异步编程和变量捕获机制**,是考察候选人对 C# 特性和底层机制理解深度的好题目。

---

### 💼 面试题:闭包陷阱与异步执行

**题目:**

请分析以下代码并回答输出结果,同时解释原因。如果结果不符合预期,请说明如何修改代码以达到预期行为。

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

class Program
{
static async Task Main(string[] args)
{
for (var i = 0; i < 5; i++)
{
Task.Run(async () =>
{
await Task.Delay(100); // 模拟异步操作
Console.WriteLine(i);
});
}

await Task.Delay(1000); // 等待所有任务完成
}
}
```

---

### ✅ 考察点:

- **变量捕获(Variable Capture)与闭包(Closure)**
- **循环中使用异步 lambda 表达式**
- **`var` 与 `int` 在循环变量捕获中的差异(C#5 以后行为变化)**
- **多线程环境下的共享变量问题**
- **如何正确捕获循环变量**

---

### 💡 正确答案与解析:

**输出结果:**

```
5
5
5
5
5
```

**解释:**

在 `for` 循环中,`i` 是一个**循环变量**,它在整个循环中是**同一个变量实例**。Lambda 表达式中引用的 `i` 是**对这个变量的引用**,而不是值的拷贝。

当 `Task.Run` 中的异步操作执行时(延迟 100 毫秒),循环已经完成,此时 `i` 的值已经是 5。所有任务都捕获了同一个变量 `i`,因此最终都打印 `5`。

---

### 🛠 如何修复这个问题?

为了让每个任务捕获当前的 `i` 值,可以在循环体内**显式创建一个副本**:

```csharp
for (var i = 0; i < 5; i++)
{
int local = i;
Task.Run(async () =>
{
await Task.Delay(100);
Console.WriteLine(local);
});
}
```

这样,每次循环都会创建一个新的 `local` 变量,每个 lambda 表达式捕获的是不同的变量,输出结果就会是:

```
0
1
2
3
4
```

---

### 🧠 进阶问题(可选追问):

1. **如果将 `var i = 0` 改为 `int i = 0`,结果会不会不同?为什么?**
- 不会。`var` 和 `int` 在这里是等价的,关键在于变量作用域和捕获方式。

2. **如果使用 `foreach` 循环代替 `for`,结果会怎样?为什么?**
- 在 C#5 及以后,`foreach` 循环变量默认是“每次迭代都创建新变量”,因此不会出现这种捕获问题。

3. **如何使用 `ValueTask` 替代 `Task` 来优化性能?**

---

如果你能清晰地解释上述行为和修复方式,说明你对 C# 的闭包机制、异步编程和语言细节有深入理解,是专家级 C# 开发者的水平。

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

上一篇: c#题例-2025-08-02 20:58:41

下一篇: c#题例-2025-08-02 09:52:13

精华推荐