CSharp-Learning/notes/10_Delegates_and_Events.md

183 lines
3.9 KiB
Markdown
Raw Normal View History

# 第十课:委托和事件
## 委托Delegate是什么
委托 = 函数的"容器",可以把函数当作变量传递。
```csharp
// 声明委托类型
delegate int Calculator(int a, int b);
// 定义符合委托的方法
int Add(int a, int b) => a + b;
int Multiply(int a, int b) => a * b;
// 使用委托
Calculator calc = Add;
int result = calc(1, 2); // result = 3
calc = Multiply;
result = calc(3, 4); // result = 12
```
## 为什么需要委托
```csharp
// 场景:数组遍历时对每个元素做操作
void ProcessNumbers(int[] numbers, ??? operation)
{
foreach (int n in numbers)
{
??? result = operation(n);
Console.WriteLine(result);
}
}
// 没有委托,你需要写多个重载
// 有委托,可以传任意操作
ProcessNumbers(nums, x => x * 2); // 翻倍
ProcessNumbers(nums, x => x + 1); // +1
ProcessNumbers(nums, x => x * x); // 平方
```
## Action 和 Func简化委托
```csharp
// Action: 返回 void 的委托
Action<string> print = (msg) => Console.WriteLine(msg);
print("Hello"); // 无返回值
// Func: 有返回值的委托
Func<int, int, int> add = (a, b) => a + b;
int result = add(1, 2); // 3
// 多参数
Func<string, string, string> concat = (a, b) => a + b;
string s = concat("Hello", " World"); // "Hello World"
```
## 事件Event是什么
事件 = 委托的升级版,只能 += 添加监听,不能外部直接调用。
```csharp
class Button
{
// 事件声明
public event Action Clicked;
public void OnClick()
{
Console.WriteLine("按钮被点击");
// 触发事件(只能在类内部)
Clicked?.Invoke();
}
}
```
```csharp
// 使用事件
Button btn = new Button();
// 添加监听者
btn.Clicked += () => Console.WriteLine("Handler 1 执行");
btn.Clicked += () => Console.WriteLine("Handler 2 执行");
btn.OnClick();
// 输出:
// 按钮被点击
// Handler 1 执行
// Handler 2 执行
```
## 事件 + 委托的应用场景
```csharp
class Microphone
{
// 事件声明
public event Action<string> OnTranscriptReady; // 识别出文字时触发
public event Action OnListeningStarted;
public event Action OnListeningStopped;
private bool isListening;
public void StartListening()
{
isListening = true;
Console.WriteLine("麦克风开始监听...");
OnListeningStarted?.Invoke();
}
public void StopListening()
{
isListening = false;
Console.WriteLine("麦克风停止监听...");
OnListeningStopped?.Invoke();
}
// 模拟识别到文字
public void TranscriptDetected(string text)
{
Console.WriteLine($"识别到: {text}");
OnTranscriptReady?.Invoke(text); // 触发事件,通知所有监听者
}
}
```
```csharp
// 使用
Microphone mic = new Microphone();
// 订阅事件
mic.OnTranscriptReady += (text) =>
{
Console.WriteLine($"收到文字: {text}");
};
mic.OnListeningStarted += () =>
{
Console.WriteLine("开始记录...");
};
mic.OnListeningStopped += () =>
{
Console.WriteLine("停止记录");
};
// 触发
mic.StartListening();
mic.TranscriptDetected("今天天气不错");
mic.TranscriptDetected("大家一起加油");
mic.StopListening();
```
## 事件 vs 委托
| | 委托 | 事件 |
|---|---|---|
| 外部添加监听 | ✓ | ✓ |
| 外部调用 | ✓ | ✗ |
| 主要用途 | 传递函数 | 通知机制 |
## 移除监听
```csharp
Action handler = () => Console.WriteLine("Handler");
btn.Clicked += handler;
btn.Clicked -= handler; // 移除
```
## 实际项目结构
```
语音识别服务
├── OnTranscriptReady(text) → UI 更新文字
├── OnListeningStarted() → UI 显示监听状态
├── OnListeningStopped() → UI 停止动画
└── OnError(error) → UI 显示错误
```
事件让各部分解耦,不需要互相引用。