Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-08-10 08:31:49

当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涉及到 **委托、事件、闭包、线程安全、异步编程、捕获上下文**等多个高级概念:

---

### 🧠 面试题:闭包陷阱与异步事件的陷阱

**题目:**

考虑以下 C# 控制台程序:

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

class Program
{
static void Main(string[] args)
{
var service = new EventService();

for (int i = 0; i < 5; i++)
{
int counter = i;
Task.Run(async () =>
{
await Task.Delay(100); // 模拟异步操作
service.OnUpdate += (s, e) =>
{
Console.WriteLine($"Task {counter}: {e.Message}");
};
});
}

service.RaiseEvent("Hello");
Console.ReadLine();
}
}

public class EventService
{
public event EventHandler OnUpdate;

public void RaiseEvent(string message)
{
OnUpdate?.Invoke(this, new UpdateEventArgs { Message = message });
}
}

public class UpdateEventArgs : EventArgs
{
public string Message { get; set; }
}
```

---

### ❓问题:

**1. 请分析这段代码输出的结果(如果有的话),并解释为什么?**

**2. 如果我们期望每个 Task 注册的事件处理器都能输出正确的 `counter` 值,应该如何修改代码?**

**3. 当前的事件注册方式是否线程安全?为什么?应如何改进以确保线程安全?**

---

### 🎯 难点解析(供面试官参考):

1. **闭包捕获陷阱**:`counter` 是在循环中定义的局部变量,被多个 Task 中的 lambda 表达式捕获。由于 Task 是异步执行的,当它们真正执行时,`counter` 的值可能已经改变,导致所有 Task 都捕获到相同的最终值(例如 4)。

2. **异步与事件注册时机**:由于事件注册发生在异步 Task 中,而 `RaiseEvent` 是在主线程中立即调用的,可能导致事件尚未注册就被触发,从而部分或全部事件监听器未生效。

3. **线程安全问题**:多线程中使用 `+=` 操作符来注册事件是非原子操作,可能导致竞态条件。`event` 使用默认的 `EventHandler` 实现时,虽然 `+=` 和 `-=` 是线程安全的(使用了 `Interlocked.CompareExchange`),但在某些自定义事件实现中可能不是线程安全的。

---

### ✅ 理想回答要点:

- 正确识别闭包捕获变量的陷阱,并提出在循环体内复制变量(如 `int copy = counter;`)以确保每个 lambda 捕获不同的变量副本。
- 提出使用 `await Task.Run(...)` 替代 `Task.Run(...)` 并等待所有任务完成,以确保事件注册完成后再触发事件。
- 提出使用 `lock` 或者使用 `ConcurrentDictionary` 等方式来线程安全地管理事件订阅。
- 对 C# 中的闭包机制、异步编程模型(async/await)、事件线程安全等有深入理解。

---

### 💡 延伸讨论(可选):

- 如何使用 `WeakReference` 来避免内存泄漏?
- 如何设计一个线程安全的事件聚合器(Event Aggregator)?
- 在 .NET Core/.NET 5+ 中,`event` 的线程安全性是否有变化?
- 如何使用 `IProgress` 替代事件机制来避免这些问题?

---

如果你需要,我也可以提供这道题的标准答案和优化后的代码实现。是否需要?

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

上一篇: c#题例-2025-08-10 17:49:54

下一篇: c#题例-2025-08-10 02:58:30

精华推荐