c#题例-2025-07-25 22:18:36
日期: 2025-07-25 分类: AI写作 31次阅读
当然可以!下面是一道**专家级别**的 C# 逻辑面试题,涵盖了 **委托、事件、闭包、异步编程、线程安全** 等多个高级知识点,适合考察候选人对 C# 语言和 .NET 平台的深入理解。
---
### 🧠 面试题:事件订阅与闭包陷阱(Event Subscription and Closure Pitfall)
#### 题目描述:
考虑以下 C# 控制台应用程序代码:
```csharp
using System;
using System.Threading.Tasks;
class Program
{
public static event EventHandler
static async Task Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
int copy = i;
Notify += (sender, message) =>
{
Console.WriteLine($"Subscriber {copy} received: {message}");
};
}
await TriggerNotificationsAsync();
}
static async Task TriggerNotificationsAsync()
{
foreach (var handler in Notify.GetInvocationList())
{
await Task.Run(() => handler.DynamicInvoke(null, "Hello"));
await Task.Delay(100); // 模拟异步延迟
}
}
}
```
#### 问题一:
1. 这段代码的输出是什么?为什么?
#### 问题二:
2. 如果将 `int copy = i;` 改为 `var copy = i;`,是否会影响输出?为什么?
#### 问题三:
3. 如果不使用 `int copy = i;`,如何修改代码,确保每个订阅者都能打印出它被注册时的正确 `i` 值?
#### 问题四:
4. 假设 `Notify` 是一个被多个组件广泛使用的事件,如何确保事件订阅和取消订阅是线程安全的?请提供一个线程安全的封装方式。
---
### ✅ 考察点解析:
| 知识点 | 说明 |
|--------|------|
| 闭包与变量捕获 | 考察对 lambda 表达式中变量捕获的理解,特别是循环变量的陷阱 |
| 事件与委托 | 了解 `event`, `EventHandler`, `GetInvocationList()` 等机制 |
| 异步编程 | 使用 `Task.Run` 和 `await` 调用事件处理器 |
| 线程安全 | 如何安全地管理事件的订阅和取消订阅(特别是在多线程环境下) |
---
### 💡 参考答案简要(如需完整讲解可继续提问):
#### 回答一:
输出为:
```
Subscriber 0 received: Hello
Subscriber 1 received: Hello
Subscriber 2 received: Hello
Subscriber 3 received: Hello
Subscriber 4 received: Hello
```
这是因为 `int copy = i;` 强制创建了一个新的变量副本,避免了闭包陷阱。
#### 回答二:
将 `int copy = i;` 改为 `var copy = i;` 不会影响输出。因为 `var` 在这里是 `int` 类型推断,效果等价。
#### 回答三:
如果不使用 `copy`,可以使用 lambda 表达式传入 `i` 作为参数,例如:
```csharp
Notify += (sender, message) =>
{
int copy = i;
Console.WriteLine($"Subscriber {copy} received: {message}");
};
```
或者使用 `foreach` 循环(C# 5+)自动捕获当前值。
#### 回答四:
使用 `lock` 或 `EventHandlerList` 类来封装事件,确保线程安全地添加/移除订阅者。
---
如果你希望我提供这道题目的完整讲解或扩展更多类似题目(如涉及 `async/await` 深层陷阱、`ConfigureAwait`、`WeakReference` 缓存、泛型委托等),欢迎继续提问!
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
标签:AI写作
精华推荐