Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-07-14 12:59:39

当然可以!以下是一道**专家级别**的 C# 逻辑面试题,涉及 **委托、泛型、异步编程、闭包捕获、线程安全**等多个高级语言特性,同时考察对 .NET 运行时行为的理解。

---

### 🧠 面试题:深入理解异步委托与变量捕获

#### 💬 题目:

考虑以下 C# 代码片段:

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

class Program
{
static void Main()
{
for (var i = 0; i < 5; i++)
{
int counter = i;
Task.Run(() =>
{
Console.WriteLine(counter);
Task.Delay(100).Wait();
Console.WriteLine($"After delay: {counter}");
});
}

Console.ReadLine(); // 防止主线程退出
}
}
```

#### ✅ 问题一:
请说明上述代码的输出结果(包括顺序是否固定)并解释原因。

#### ✅ 问题二:
如果将 `int counter = i;` 改为 `var counter = i;`,结果会变化吗?为什么?

#### ✅ 问题三:
现在我们想让每个任务在延迟后打印的是它启动时的 `counter` 值。但目前所有任务都可能输出相同的 `counter`(比如多个 "After delay: 4")。如何修改这段代码以确保每个任务都能正确地记住它自己的 `counter` 值?

#### ✅ 问题四(进阶):
如果不使用局部变量复制(即不写 `int counter = i;`),而是希望保留循环变量 `i`,你能否通过其他方式保证每个任务捕获到正确的值?写出实现方法并解释其原理。

---

### 🔍 考察点解析:

| 考察内容 | 知识点 |
|----------|--------|
| 变量捕获 | Lambda 表达式中对外部变量的捕获机制 |
| 异步任务调度 | Task.Run 的线程池行为及执行顺序不确定性 |
| 闭包陷阱 | 在循环中直接使用循环变量导致的问题 |
| 泛型与类型推断 | var 与具体类型的差异(尤其在闭包中的影响) |
| 线程安全 | 多个 Task 同时访问共享状态的行为分析 |

---

### 💡 示例答案要点(供参考):

#### 回答一:
- 输出顺序不确定,因为任务是在线程池上并发执行。
- `"After delay: {counter}"` 中的值始终等于初始输出值,因为 `counter` 是在每次迭代中定义的局部变量,被捕获为副本。
- 使用 `int counter = i;` 实际上创建了新的变量,避免了“闭包陷阱”。

#### 回答二:
- 不会变化,`var counter = i;` 会被编译器推断为 `int` 类型,效果相同。

#### 回答三:
- 已经解决了该问题,不需要修改。

#### 回答四:
- 可以通过将循环变量复制到局部作用域中,或使用参数传递的方式避免捕获问题,例如:

```csharp
for (var i = 0; i < 5; i++)
{
Task.Run(() =>
{
int local = i;
Console.WriteLine(local);
Task.Delay(100).Wait();
Console.WriteLine($"After delay: {local}");
});
}
```

> ⚠️ 注意:这仍然有风险,因为 `i` 是被多个线程读取的共享变量。虽然 `int` 是只读的,不会有竞态条件,但在某些复杂场景下仍需注意同步。

---

如果你需要更多类似级别的题目,我可以继续出关于 **表达式树、LINQ 优化、内存泄漏排查、协变逆变、ref returns/locals、unsafe code** 等方向的题目。欢迎继续提问!

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

上一篇:无

下一篇: c#题例-2025-07-14 07:26:22

精华推荐