c#题例-2025-07-09 16:58:48
日期: 2025-07-09 分类: AI写作 5次阅读
当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涉及到 **委托、泛型、异步编程、闭包捕获、线程安全与延迟执行**等多个高级语言特性,适合考察候选人对 C# 和 .NET 底层机制的理解。
---
### 🧠 面试题:深入理解委托、闭包与异步行为
#### 问题描述:
以下是一个使用 `async/await` 和 `Func
```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var funcs = new List
for (int i = 0; i < 3; i++)
{
int counter = i * 10;
await Task.Delay(100); // 模拟异步操作
funcs.Add(async () =>
{
await Task.Delay(100);
return ++counter;
});
}
foreach (var func in funcs)
{
Console.WriteLine(await func());
}
}
}
```
---
### ✅ 考察点:
- 对 `async/await` 异步模型和线ambda表达式中变量捕获(闭包)的理解。
- 是否了解 C# 中捕获的是变量本身而不是值(即闭包引用捕获)。
- 对 `Task.Delay` 的作用以及其在异步流程中的影响。
- 对多线程/并发访问共享变量是否线程安全的认知(虽然在这个例子中不是并发执行,但理解顺序很重要)。
- 对 `Func
---
### 💡 正确答案与解析:
**输出结果:**
```
1
2
3
```
或者更准确地说,每个调用返回的是递增后的值,因此最终是:
```
11
21
31
```
❌ **错误理解**:很多开发者会误以为输出是 `10, 20, 30` 或者 `11, 11, 11`。
✅ **正确理解:**
- 变量 `counter` 是在循环内部声明的局部变量,但由于它被 lambda 表达式捕获,C# 编译器会将其提升为一个**闭包类**中的字段(也就是说,lambda 捕获的是变量的引用,而不是值)。
- 每次循环迭代都会创建一个新的 `counter` 变量(因为它是进入循环体后定义的),所以每个 lambda 实际上捕获的是**不同的变量实例**。
- 因此,三个 lambda 各自拥有自己的 `counter` 变量副本,分别初始化为 `0`, `10`, `20`。
- 最终每个 lambda 返回的是各自 `++counter` 的结果:
- 第一个 lambda 返回 `0 + 1 = 1`
- 第二个返回 `10 + 1 = 11`
- 第三个返回 `20 + 1 = 21`
> ⚠️ 如果题目改为 `for (int i = 0; i < 3; i++) { ... }` 且 `counter = i * 10` 改为直接使用 `i`,则会出现经典的闭包陷阱,所有 lambda 共享同一个 `i`,导致输出全是 `3` 或 `31`。
---
### 🎯 扩展追问(进阶):
你可以继续问候选人以下几个问题来深入探讨:
1. 如果去掉 `int counter = i * 10;`,而直接在 lambda 中使用 `i`,输出会发生什么变化?为什么?
2. 如何确保每次 lambda 捕获的都是当前值而不是引用?
3. 如果这些 lambda 并行执行(如通过 `Task.WhenAll()`),结果是否仍能保持一致?如何保证线程安全?
4. 如果把 `return ++counter;` 改成 `return counter++;`,结果会有什么不同?
---
如果你希望我再出一道类似的难题(例如涉及 LINQ、表达式树、动态类型或 unsafe 代码),欢迎告诉我!
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
上一篇:无
精华推荐