Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-07-13 20:19:49

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

---

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

**题目描述:**

你有一个类 `EventPublisher`,它每隔一秒发布一次事件,并传递当前计数器值。订阅者使用 lambda 表达式注册处理程序,并打印出接收到的值。

请分析以下代码的输出行为,并指出其中潜在的问题(至少两个),并提出修复方案。

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

public class EventPublisher
{
public event EventHandler Tick;

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` 是同步委托,但在异步 lambda 中使用时,事件调用是同步还是异步?是否存在并发问题?

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 handler in Tick.GetInvocationList())
{
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

上一篇: c#题例-2025-07-14 01:52:56

下一篇: c#题例-2025-07-13 13:31:54

精华推荐