Young87

SmartCat's Blog

So happy to code my life!

游戏开发交流QQ群号60398951

当前位置:首页 >AI写作

c#题例-2025-07-12 08:32:20

当然可以!下面是一道**专家级别**的 C# 逻辑面试题,涉及 **委托、事件、闭包、异步编程和线程安全** 的综合理解:

---

### 🧠 面试题:分析并修复以下代码中的潜在问题

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

class Program
{
public static event EventHandler SimpleEvent;

static async Task Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
int capture = i;
SimpleEvent += (sender, e) =>
{
Console.WriteLine($"Handler {capture} invoked on thread {Environment.CurrentManagedThreadId}");
};

await Task.Run(() =>
{
SimpleEvent?.Invoke(null, EventArgs.Empty);
});
}

Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
```

---

### ✅ 面试要求:

1. **解释这段代码本意是什么?**
2. **指出其中至少三个潜在问题或隐患(包括但不限于线程安全、闭包陷阱、事件内存泄漏等)?**
3. **如何修改代码以解决这些问题?**

---

### 💡 提示关键词:

- 捕获变量(captured variable)与闭包陷阱
- 多线程中访问 UI 或共享资源
- `event` 的线程安全性
- 异步调用中未取消订阅可能导致内存泄漏
- `Invoke` 是否在正确的上下文执行(如 UI 线程)

---

### 📌 参考答案概要(供面试官参考):

#### 1. 代码意图:
该程序试图注册多个事件处理函数,并在异步任务中触发这些处理函数。期望输出是每个 handler 打印出对应的编号和线程 ID。

#### 2. 存在的问题:

| 问题 | 描述 |
|------|------|
| **闭包捕获陷阱** | 使用了循环变量 `i`,没有正确使用局部副本 `capture = i`,可能导致所有 handler 输出相同的值(尽管这里用了 capture,但仍然要注意是否真的解决了问题)。 |
| **线程不安全地访问控制台** | 多个线程同时调用 `Console.WriteLine`,虽然不是致命错误,但在某些环境中会导致输出混乱。 |
| **事件未取消订阅** | 所有 handler 始终添加到静态事件中,可能导致内存泄漏(尤其是如果对象生命周期较长时)。 |
| **未处理异常和空事件** | 虽然使用了 `SimpleEvent?.Invoke(...)`,但如果 handler 中抛出异常会影响后续 handler 的执行。 |
| **事件处理逻辑可能在非预期上下文中运行** | 如果未来这个事件用于 UI 场景,那么 handler 应该调度回 UI 线程。 |

#### 3. 改进后的代码示例:

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

class Program
{
public static event EventHandler SimpleEvent;

static async Task Main(string[] args)
{
var handlers = new Action[5];

for (int i = 0; i < 5; i++)
{
int capture = i;
Action handler = (sender, e) =>
{
// 锁定控制台避免输出混乱
lock (Console.Out)
{
Console.WriteLine($"Handler {capture} invoked on thread {Environment.CurrentManagedThreadId}");
}
};

handlers[capture] = handler;
SimpleEvent += handler;

await Task.Run(() =>
{
SimpleEvent?.Invoke(null, EventArgs.Empty);
});
}

// 清理事件防止内存泄漏
foreach (var handler in handlers)
{
SimpleEvent -= handler;
}

Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
```

---

### 🔍 考察点总结:

| 技术点 | 考察目的 |
|--------|-----------|
| 委托与事件机制 | 是否理解 C# 中事件模型及线程安全调用方式 |
| 闭包捕获 | 是否了解 lambda 表达式在循环中捕获变量的行为 |
| 异步编程 | 是否熟悉 `async/await` 和多线程协作 |
| 线程安全 | 是否注意并发访问共享资源(如 Console) |
| 内存管理 | 是否考虑事件引发的对象生命周期问题 |

---

如果你需要更多类似难度的题目(比如结合 LINQ、表达式树、反射、泛型约束等),我也可以继续提供。

除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: c#题例-2025-07-12 15:18:28

下一篇: c#题例-2025-07-12 02:58:42

精华推荐