c#题例-2025-07-17 16:51:48
日期: 2025-07-17 分类: AI写作 13次阅读
当然可以!下面是一道**专家级别**的 C# 逻辑面试题,考察的内容包括:**委托、事件、闭包、异步编程、线程安全以及对 C# 语言底层机制的理解**。
---
### 🧠 面试题:事件订阅与闭包陷阱(Event Subscription and Closure Gotcha)
#### **题目描述:**
你被要求分析以下 C# 代码,并回答输出结果。
```csharp
using System;
using System.Threading.Tasks;
public class EventPublisher
{
public event EventHandler
public void UpdateValue(int value)
{
ValueUpdated?.Invoke(this, value);
}
}
public class Program
{
public static async Task Main()
{
var publisher = new Eventibrator();
for (int i = 0; i < 5; i++)
{
int copy = i;
publisher.ValueUpdated += (sender, val) =>
{
Console.WriteLine($"Handler {copy} invoked with value: {val}");
};
}
await Task.Run(() =>
{
for (int i = 1; i <= 3; i++)
{
publisher.UpdateValue(i);
}
});
Console.WriteLine("Done.");
}
}
```
---
#### **问题:**
1. **这段代码的输出结果是什么?**
2. **如果将 `int copy = i;` 这一行删除,改为直接使用 `i`,结果会怎样?为什么?**
3. **如果将事件订阅改为异步委托(`async (sender, val)`),并加入 `await Task.Delay(100)`,会出现什么问题?如何修复?**
---
### ✅ 参考答案:
#### 1. 原始代码输出:
```
Handler 0 invoked with value: 1
Handler 1 invoked with value: 1
Handler 2 invoked with value: 1
Handler 3 invoked with value: 1
Handler 4 invoked with value: 1
Handler 0 invoked with value: 2
Handler 1 invoked with value: 2
Handler 2 invoked with value: 2
Handler 3 invoked with value: 2
Handler 4 invoked with value: 2
Handler 0 invoked with value: 3
Handler 1 invoked with value: 3
Handler 2 invoked with value: 3
Handler 3 invoked with value: 3
Handler 4 invoked with value: 3
Done.
```
**解释:**
- 每个事件订阅者都捕获了一个局部变量 `copy`,它在每次循环中被赋值为 `i` 的当前值。
- 因为有显式的拷贝 `int copy = i;`,所以闭包捕获的是当前值,不会受到后续 `i` 变化的影响。
#### 2. 如果删除 `int copy = i;`,直接使用 `i`:
修改为:
```csharp
publisher.ValueUpdated += (sender, val) =>
{
Console.WriteLine($"Handler {i} invoked with value: {val}");
};
```
**输出会变为:**
```
Handler 5 invoked with value: 1
Handler 5 invoked with value: 1
Handler 5 invoked with value: 1
Handler 5 invoked with value: 1
Handler 5 invoked with value: 1
...
```
**原因:**
- 这是一个经典的闭包陷阱(**Closure Capturing Loop Variable**)。
- 所有委托都引用了同一个变量 `i`,而循环结束后 `i == 5`,因此所有闭包读取的都是最终的值。
#### 3. 如果事件订阅改为异步并加入延迟:
```csharp
publisher.ValueUpdated += async (sender, val) =>
{
await Task.Delay(100);
Console.WriteLine($"Handler {copy} invoked with value: {val}");
};
```
**可能出现的问题:**
- 由于事件调用是同步的(`ValueUpdated?.Invoke(...)`),所有事件处理会被串行执行。
- 如果某个事件处理抛出异常,会影响后续订阅者的执行。
- 如果事件订阅者是异步的,而调用者没有等待它们完成,可能导致**竞态条件**或**日志顺序混乱**。
**修复建议:**
- 不要直接使用同步 `Invoke` 调用异步事件。
- 改为使用 `Task` 返回的异步事件模式,例如使用 `async/await` 包装事件处理,或使用 `EventAggregator` 等高级模式进行事件解耦。
---
### 🧩 总结考点:
| 考察点 | 描述 |
|--------|------|
| 闭包捕获 | 是否理解变量捕获和延迟执行问题 |
| 事件机制 | 是否了解事件的同步调用机制 |
| 异步编程 | 是否了解 `async void` 的风险 |
| 线程安全 | 是否理解多线程环境下的变量共享问题 |
| 语言细节 | 是否掌握 C# 中变量作用域、lambda 表达式等机制 |
---
如果你需要更多类似难度的题目(如泛型约束、反射、表达式树、性能优化、GC、内存泄漏等),我可以继续出题!
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐