c#题例-2025-07-04 20:59:08
日期: 2025-07-04 分类: AI写作 33次阅读
当然可以!以下是一道**专家级别**的 C# 程序员逻辑面试题,涉及 **委托、事件、异步编程、闭包捕获和线程安全**等多个高级概念:
---
### 🧠 面试题:异步委托与闭包陷阱
**题目描述:**
请分析下面的 C# 代码,并回答问题。
```csharp
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 5; i++)
{
Task.Run(() =>
{
Console.WriteLine(i);
});
}
Console.ReadKey();
}
}
```
#### ❓问题1:
这段代码的输出是什么?为什么?
#### ❓问题2(进阶):
如何修改代码以确保每个任务都输出其对应的循环变量值(即 0 到 4)?
#### ❓问题3(扩展):
如果将 `Task.Run` 替换为 `Task.Factory.StartNew`,是否会影响结果?为什么?
#### ❓问题4(挑战):
假设你不能修改循环体内的代码,也不能使用 `let` 变量(如在 `for` 中定义局部变量),你能否通过其他方式(如使用闭包参数传递、冻结变量等)保证输出正确?
---
### ✅ 参考答案概要:
#### 回答1:
输出可能为多个 `5`,因为 `i` 是被闭包捕获的循环变量。当 `Task.Run` 异步执行时,`i` 已经递增完成,最终值是 5。所有任务访问的是同一个变量 `i`,而不是当时的值快照。
#### 回答2:
在每次循环中创建一个副本:
```csharp
for (var i = 0; i < 5; i++)
{
int loopCopy = i;
Task.Run(() => Console.WriteLine(loopCopy));
}
```
或者使用 `foreach` + 局部变量(C# 5.0+ 的行为更直观)。
#### 回答3:
`Task.Factory.StartNew` 和 `Task.Run` 在这种场景下行为相同,仍会受闭包捕获影响,因此不会改变结果。
#### 回答4:
可以通过封装到方法中传参实现:
```csharp
void RunTask(int value)
{
Task.Run(() => Console.WriteLine(value));
}
// 修改主循环:
for (var i = 0; i < 5; i++)
{
RunTask(i);
}
```
此时每次调用 `RunTask(i)` 会将当前 `i` 的值拷贝给形参 `value`,形成独立闭包。
---
### 💡考察点总结:
- 对 **闭包捕获机制** 的理解
- 对 **异步任务调度与线程安全** 的掌握
- **变量生命周期与作用域**
- 是否了解 **C# 循环变量捕获的历史变化(C# 5 vs C# 4)**
- 能否灵活运用 **委托与函数式编程技巧** 解决实际问题
---
如果你需要更多类似级别的题目(例如涉及 LINQ 表达式树、泛型约束、内存泄漏、await/async 控制流、协变逆变等),我可以继续为你出题 😄
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐