CSharp-Learning/notes/10_Delegates_and_Events.md
Rosmontis_Cloud f604d53191 Initial commit: C# 学习笔记和示例代码
- Lesson 01-10: C# 基础语法
- WebView2: 集成示例
- notes/: 详细笔记
2026-07-01 16:31:35 +08:00

3.9 KiB
Raw Blame History

第十课:委托和事件

委托Delegate是什么

委托 = 函数的"容器",可以把函数当作变量传递。

// 声明委托类型
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

为什么需要委托

// 场景:数组遍历时对每个元素做操作
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简化委托

// 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是什么

事件 = 委托的升级版,只能 += 添加监听,不能外部直接调用。

class Button
{
    // 事件声明
    public event Action Clicked;

    public void OnClick()
    {
        Console.WriteLine("按钮被点击");
        // 触发事件(只能在类内部)
        Clicked?.Invoke();
    }
}
// 使用事件
Button btn = new Button();

// 添加监听者
btn.Clicked += () => Console.WriteLine("Handler 1 执行");
btn.Clicked += () => Console.WriteLine("Handler 2 执行");

btn.OnClick();
// 输出:
// 按钮被点击
// Handler 1 执行
// Handler 2 执行

事件 + 委托的应用场景

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);  // 触发事件,通知所有监听者
    }
}
// 使用
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 委托

委托 事件
外部添加监听
外部调用
主要用途 传递函数 通知机制

移除监听

Action handler = () => Console.WriteLine("Handler");

btn.Clicked += handler;
btn.Clicked -= handler;  // 移除

实际项目结构

语音识别服务
    ├── OnTranscriptReady(text)      → UI 更新文字
    ├── OnListeningStarted()          → UI 显示监听状态
    ├── OnListeningStopped()          → UI 停止动画
    └── OnError(error)               → UI 显示错误

事件让各部分解耦,不需要互相引用。