c#题例-2025-07-21 18:58:31
日期: 2025-07-21 分类: AI写作 16次阅读
当然可以!下面是一道**专家级别**的 C# 程序员逻辑面试题,涵盖了 **委托、事件、闭包、线程安全、异步编程、内存管理**等多个高级概念,适合考察候选人对 C# 语言及其运行机制的深入理解。
---
### 🧠 面试题:事件与闭包的陷阱
**题目:**
请看以下 C# 代码:
```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class EventRaiser
{
public event EventHandler
public async Task RaiseEventAsync()
{
await Task.Delay(100); // 模拟异步操作
OnEvent(this, EventArgs.Empty);
}
}
public class TestClass
{
private List
public void Start()
{
var raiser = new EventRaiser();
EventHandler
{
await Task.Delay(500); // 模拟耗时操作
Console.WriteLine("Event handled.");
};
raiser.OnEvent += handler;
_subscriptions.Add(new DisposableAction(() =>
{
raiser.OnEvent -= handler;
Console.WriteLine("Unsubscribed.");
}));
raiser.RaiseEventAsync();
}
public void Stop()
{
foreach (var d in _subscriptions)
{
d.Dispose();
}
_subscriptions.Clear();
}
private class DisposableAction : IDisposable
{
private readonly Action _action;
public DisposableAction(Action action)
{
_action = action;
}
public void Dispose()
{
_action?.Invoke();
}
}
}
```
然后在主程序中执行如下代码:
```csharp
var test = new TestClass();
test.Start();
test.Stop();
```
---
### ❓问题:
1. 上述代码是否存在**内存泄漏**的风险?为什么?
2. 如果在 `Start()` 中多次调用 `test.Start()`,会发生什么?是否会导致多次订阅?
3. 在 `handler` 中使用 `async void`(即 `EventHandler
4. 如何改进这段代码,使其线程安全且避免内存泄漏?
---
### 🧩 考察点:
- **事件订阅的生命周期管理**
- **使用闭包导致对象无法释放的问题**
- **async void 的陷阱与异常处理**
- **IDisposable 的正确使用方式**
- **垃圾回收机制和对象引用链**
- **异步事件处理的正确模式**
---
### ✅ 参考答案(简要):
1. **是的,存在内存泄漏。**
因为 `raiser.OnEvent += handler;` 会强引用 `handler`,而 `handler` 是一个 lambda 表达式,它捕获了 `raiser` 对象(或者至少是 `TestClass` 的某些状态),导致 `raiser` 无法被释放,除非手动取消订阅。
2. **多次调用 `Start()` 会导致重复订阅。**
每次调用 `Start()` 都会创建一个新的 `raiser` 实例并订阅事件,但 `_subscriptions` 列表中只添加了一个 `DisposableAction`,但无法跟踪之前的 `raiser` 实例,因此旧的订阅无法取消,导致多个事件触发。
3. **不安全。**
`EventHandler` 是 `async void`,这意味着异常无法被捕获,且会直接抛到同步上下文中,可能导致程序崩溃。
4. **改进建议:**
- 使用 `async Task` 替代 `async void`,并在事件中使用 `Task.Run` 或其他机制处理异步逻辑。
- 使用弱引用事件模式(如 `WeakEventManager`)来避免内存泄漏。
- 确保每次 `Start()` 都清理之前的订阅。
- 使用 `CancellationToken` 来取消异步操作。
---
如果你需要我提供改进后的代码示例,也可以告诉我 😊
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐