Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-07-06 07:31:48

当然可以!以下是一道**专家级别**的 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`、`Interlocked`)。
- 如果只是输出,可以考虑使用 `Console.Out.Write` 并加锁包装,避免输出交错。
- 使用 `ThreadLocal` 来隔离线程上下文数据。

---

### 💡 考察点总结:

| 技术点 | 是否考察 |
|--------|----------|
| 委托与 Lambda 行为 | ✅ |
| 闭包与变量捕获机制 | ✅ |
| 值类型 vs 引用语义 | ✅ |
| 多线程与并发控制 | ✅✅(进阶) |
| 对 .NET 编译器行为的理解 | ✅ |

---

需要我再出一道更偏向设计模式、性能优化、或者异步编程方面的高级题目吗?

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

上一篇: c#题例-2025-07-06 14:18:36

下一篇: c#题例-2025-07-06 01:58:30

精华推荐