c#题例-2025-07-13 20:19:49
日期: 2025-07-13 分类: AI写作 65次阅读
当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涉及 **委托、事件、异步编程、闭包陷阱和线程安全**等多个高级概念:
---
### 🧠 面试题:异步事件与闭包陷阱
**题目描述:**
你有一个类 `EventPublisher`,它每隔一秒发布一次事件,并传递当前计数器值。订阅者使用 lambda 表达式注册处理程序,并打印出接收到的值。
请分析以下代码的输出行为,并指出其中潜在的问题(至少两个),并提出修复方案。
```csharp
using System;
using System.Threading.Tasks;
public class EventPublisher
{
public event EventHandler
public async Task StartAsync()
{
int counter = 0;
while (true)
{
await Task.Delay(1000);
OnTick(++counter);
}
}
protected virtual void OnTick(int value)
{
Tick?.Invoke(this, value);
}
}
class Program
{
static async Task Main(string[] args)
{
var publisher = new EventPublisher();
int subscriptionId = 0;
for (int i = 0; i < 3; i++)
{
int localCopy = i;
publisher.Tick += async (sender, e) =>
{
await Task.Delay(500); // 模拟异步处理
Console.WriteLine($"Handler {localCopy}: Tick {e}");
};
Console.WriteLine($"Subscribed handler {localCopy}");
}
await publisher.StartAsync();
}
}
```
---
### ✅ 考察点解析:
1. **闭包陷阱(Closure Issue)**
- 在循环中使用局部变量 `i` 或 `localCopy` 的 lambda 函数可能会导致所有处理程序捕获到相同的值。
- 实际上这里已经用 `localCopy = i` 来规避了这个问题,但需要确认是否真的有效。
2. **事件的线程安全问题**
- `EventHandler
3. **异步 void 的风险**
- Lambda 使用了 `async (sender, e)`,但是没有 await,这可能导致未处理异常被忽略。
4. **无限循环与取消机制缺失**
- `StartAsync()` 中的 `while (true)` 循环无法终止,实际开发中应引入 `CancellationToken`。
---
### 💡 参考答案要点:
#### 输出行为:
- 控制台将每秒打印三次消息,如:
```
Subscribed handler 0
Subscribed handler 1
Subscribed handler 2
Handler 0: Tick 1
Handler 1: Tick 1
Handler 2: Tick 1
Handler 0: Tick 2
...
```
#### 存在的问题:
1. **事件调用方式不适用于异步处理**
- 当前事件是以同步方式调用的,每个事件处理函数虽然用了 `await Task.Delay(500)`,但由于是同步调用,会阻塞后续事件处理器执行。
- 正确做法应该是使用 `Task` 返回类型并逐个 await 所有处理程序。
2. **异常处理缺失**
- 异步 void 方法无法正确传播异常,容易导致崩溃且难以调试。
3. **事件注销机制缺失**
- 没有提供 unsubscribe 功能,可能造成内存泄漏。
---
### ✅ 改进建议:
#### 1. 使用 `InvokeAsync` 模式支持异步事件:
```csharp
public async Task RaiseTickAsync(int value)
{
foreach (EventHandler
{
try
{
await handler.Invoke(this, value);
}
catch (Exception ex)
{
Console.WriteLine($"Error in handler: {ex.Message}");
}
}
}
```
然后替换 `OnTick` 调用为:
```csharp
await RaiseTickAsync(++counter);
```
#### 2. 增加取消机制:
```csharp
public async Task StartAsync(CancellationToken ct)
{
int counter = 0;
while (!ct.IsCancellationRequested)
{
await Task.Delay(1000, ct);
await RaiseTickAsync(++counter);
}
}
```
---
### 🏁 总结:
本题考察候选人对以下方面的理解和实践经验:
- 异步编程模型(async/await)
- 事件与委托的深入理解
- 闭包和变量捕获陷阱
- 多线程环境下的异常处理与资源管理
- 编写可维护、可扩展、线程安全的代码能力
---
如果你希望我再出一道类似难度的题目(比如关于表达式树、反射或性能优化),也可以告诉我!
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐