c#题例-2025-07-06 07:31:48
日期: 2025-07-06 分类: AI写作 25次阅读
当然可以!以下是一道**专家级别**的 C# 程序员逻辑面试题,它融合了委托、泛型、闭包、线程安全以及对 .NET 运行机制的理解:
---
### 🧠 面试题:理解委托捕获与闭包陷阱(Closure Gotchas)
#### **题目描述:**
请分析以下代码并回答问题。
```csharp
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var actions = new List
for (int i = 0; i < 5; i++)
{
actions.Add(() => Console.Write(i + " "));
}
foreach (var action in actions)
{
action();
}
}
}
```
#### **问题一:**
这段代码会输出什么?为什么?
#### **问题二:**
如果你希望每个 `Action` 输出的是循环变量在添加时的实际值(即:`0 1 2 3 4`),应该如何修改代码?
#### **问题三(进阶):**
如果这段代码运行在一个多线程环境中,每个 `Action` 被不同线程调用,你会如何确保输出是确定性的?请说明潜在的线程安全问题和解决方案。
---
### ✅ 参考答案概要:
#### 回答一:
输出为:`5 5 5 5 5`
**原因:**
C# 中的 lambda 表达式捕获的是变量本身(而不是变量的值)。循环结束后,`i` 的值已经是 5,所有的 `Action` 都引用了同一个 `i`,因此都打印 5。
---
#### 回答二:
修改方式如下:
```csharp
for (int i = 0; i < 5; i++)
{
int temp = i;
actions.Add(() => Console.Write(temp + " "));
}
```
或者:
```csharp
for (int i = 0; i < 5; i++)
{
int captured = i;
actions.Add(() => Console.Write(captured + " "));
}
```
这样每个 lambda 捕获的是局部变量的一个副本,从而保留当前循环迭代的值。
---
#### 回答三(进阶):
虽然在这个例子中没有共享可变状态,但如果 `Console.Write` 被替换成操作共享资源(如静态变量或集合),多个线程执行这些 `Action` 可能导致竞争条件。
**解决方案包括:**
- 使用锁(`lock`)保护共享资源。
- 使用线程安全的数据结构(如 `ConcurrentQueue
- 如果只是输出,可以考虑使用 `Console.Out.Write` 并加锁包装,避免输出交错。
- 使用 `ThreadLocal
---
### 💡 考察点总结:
| 技术点 | 是否考察 |
|--------|----------|
| 委托与 Lambda 行为 | ✅ |
| 闭包与变量捕获机制 | ✅ |
| 值类型 vs 引用语义 | ✅ |
| 多线程与并发控制 | ✅✅(进阶) |
| 对 .NET 编译器行为的理解 | ✅ |
---
需要我再出一道更偏向设计模式、性能优化、或者异步编程方面的高级题目吗?
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐