云计算百科
云计算领域专业知识百科平台

【C#零基础进阶】委托(Delegate)超详细精讲,从原理到实战全覆盖

【C#零基础进阶】委托(Delegate)超详细精讲,从原理到实战全覆盖
📌 前言
很多C#初学者在学习委托、事件、Lambda表达式时,总会感到困惑:委托到底是什么?为什么要用委托?委托和方法有什么区别?
委托是C#中面向对象、回调编程、事件机制、异步编程、框架设计的核心基础,几乎所有.NET高级特性都基于委托实现。吃透委托,才能真正理解C#的函数式编程思想、事件驱动模型。
本文将从零开始,通俗易懂讲解委托的全部核心知识点,搭配可直接运行的代码案例,帮助你们理解。


一、什么是委托?(核心定义)
1.1 官方定义
委托(Delegate)是一种用来存储、传递、调用方法的引用类型。
简单来说:委托就是方法的容器,是方法的“替身”。
1.2 通俗理解
普通变量存储的是数据(int、string、数组等);
委托变量存储的是方法(方法的地址、方法的逻辑)。
我们可以把方法赋值给委托、把委托当做参数传递、在任意位置通过委托执行对应的方法。
1.3 委托的本质

  • 委托是引用类型,继承自 System.MulticastDelegate
  • 委托是类型安全的:签名(返回值、参数列表)必须和匹配的方法完全一致
  • 委托支持多播:一个委托可以绑定多个方法,一次性批量执行

二、委托的语法与基础使用
2.1 委托的声明语法
// 语法:修饰符 delegate 返回值类型 委托名(参数列表);
public delegate void MyDelegate(string msg);
声明规则:

  • 必须以 delegate 关键字开头
  • 返回值、参数列表决定了能绑定哪些方法
  • 委托可以声明在命名空间下、类内部
    2.2 委托的基础使用三步曲
  • 声明委托类型
  • 定义匹配签名的普通方法
  • 实例化委托、绑定方法、执行委托
    2.3 完整入门案例
    using System;
  • namespace DelegateDemo
    {
    // 1. 声明委托(无返回值、string参数)
    public delegate void ShowMsgDelegate(string msg);

    class Program
    {
    static void Main(string[] args)
    {
    // 3. 实例化委托,绑定方法
    ShowMsgDelegate del = ShowMessage;

    // 执行委托(调用绑定的方法)
    del("Hello C#委托!");
    del("CSDN技术分享");
    }

    // 2. 定义和委托签名匹配的方法
    public static void ShowMessage(string message)
    {
    Console.WriteLine($"输出信息:{message}");
    }
    }

    }
    运行结果:
    输出信息:Hello C#委托!
    输出信息:CSDN技术分享


    三、委托的核心特性
    3.1 类型安全(最核心优势)
    委托会严格校验返回值类型、参数个数、参数类型、参数顺序,不匹配直接编译报错,避免了C语言函数指针的不安全问题。
    例:委托是 void (string),就不能绑定 int (int) 类型的方法。
    3.2 委托可以作为方法参数(回调核心)
    这是委托最常用、最重要的场景:将方法作为参数传递,实现回调逻辑、解耦代码。
    实战案例:通用计算器
    using System;

    namespace DelegateDemo
    {
    // 声明计算委托
    public delegate int CalcDelegate(int a, int b);

    class Program
    {
    static void Main(string[] args)
    {
    // 传递不同方法,实现不同计算逻辑
    Calc(10, 20, Add);
    Calc(10, 20, Sub);
    }

    // 通用计算方法:委托作为参数
    public static void Calc(int num1, int num2, CalcDelegate func)
    {
    int res = func(num1, num2);
    Console.WriteLine($"计算结果:{res}");
    }

    // 加法方法
    public static int Add(int a, int b) => a + b;
    // 减法方法
    public static int Sub(int a, int b) => a – b;
    }

    }
    核心优势:无需修改Calc方法,只需要传入不同方法,就能扩展新功能,完美符合开闭原则。
    3.3 多播委托(一个委托绑定多个方法)
    委托支持 +=、-= 操作,可以绑定/解绑多个方法,执行时会按绑定顺序依次执行所有方法。
    ⚠️ 注意:有返回值的多播委托,只会获取最后一个方法的返回值,前面的返回值会被丢弃,日常开发中多播委托基本都用无返回值类型。
    多播委托案例
    using System;

    namespace DelegateDemo
    {
    public delegate void MultiDelegate();

    class Program
    {
    static void Main(string[] args)
    {
    MultiDelegate del = null;

    // 绑定多个方法
    del += Method1;
    del += Method2;
    del += Method3;

    // 执行所有绑定的方法
    del();

    Console.WriteLine("=====解绑一个方法后=====");

    // 解绑方法2
    del -= Method2;
    del();
    }

    public static void Method1() => Console.WriteLine("执行方法1");
    public static void Method2() => Console.WriteLine("执行方法2");
    public static void Method3() => Console.WriteLine("执行方法3");
    }

    }


    四、.NET内置通用委托(不用手动声明)
    日常开发中,90%场景不需要自己声明委托,.NET 内置了三套通用委托,覆盖所有常用场景:
    4.1 Action 委托(无返回值)

    • Action:无参数、无返回值
    • Action<T1,T2…>:多个泛型参数、无返回值
      4.2 Func 委托(有返回值)
    • Func<返回值类型>:无参数、有返回值
    • Func<参数1,参数2…,返回值>:多参数、有返回值
      4.3 Predicate 委托(固定返回bool)
    • Predicate:接收一个参数,固定返回 bool
    • 多用于条件判断、集合筛选
      4.4 内置委托实战演示
      using System;
      using System.Collections.Generic;

    namespace DelegateDemo
    {
    class Program
    {
    static void Main(string[] args)
    {
    // Action 使用
    Action show = msg => Console.WriteLine($“Action输出:{msg}”);
    show(“测试Action委托”);

    // Func 使用
    Func<int, int, int> add = (a, b) => a + b;
    Console.WriteLine($"Func计算结果:{add(20,30)}");

    // Predicate 使用
    Predicate<int> isOdd = num => num % 2 != 0;
    Console.WriteLine($"5是否是奇数:{isOdd(5)}");
    }
    }

    }


    五、委托与Lambda表达式的关系
    Lambda表达式就是委托的简写形式,用于快速生成匿名委托方法,简化代码。
    所有Lambda表达式,最终都会编译为委托对象。
    对比写法(传统委托 vs Lambda)
    // 1. 传统匿名方法
    Func<int,int> func1 = delegate(int num)
    {
    return num * num;
    };

    // 2. Lambda简写(更简洁)
    Func<int,int> func2 = num => num * num;
    日常开发中,优先使用 Lambda + 内置委托,极少手动声明自定义委托。


    六、委托的经典使用场景

    6.1 回调方法
    异步操作完成后,通过委托回调通知结果,是异步编程的基础。
    6.2 事件驱动(Winform/WPF/Unity)
    事件本质是封装后的委托,所有按钮点击、窗口事件、Unity生命周期事件,全部基于委托实现。
    6.3 集合高级操作(LINQ)
    LINQ的 Where、Select、OrderBy 等方法,参数全部是 Func/Predicate 委托。
    List list = new List{1,2,3,4,5};
    // Where参数是Predicate委托
    var res = list.Where(x => x > 3);
    6.4 解耦代码、实现插件化
    通过委托传递逻辑,让核心代码和业务代码分离,提升代码扩展性。


    七、委托常见易错点与避坑指南
    7.1 未初始化委托导致空指针异常
    委托默认值为null,直接调用会报错,建议先判空:
    if(del != null)
    {
    del();
    }
    // 简写方式
    del?.Invoke();
    7.2 多播委托返回值丢失
    有返回值的多播委托,仅最后一个方法返回值生效,前面全部丢失,业务中尽量不用。
    7.3 委托混淆重载方法
    类中有多个重载方法时,委托绑定可能出现歧义,建议手动指定方法签名。


    八、委托与事件的区别

  • 关系:事件是私有、封装后的委托
  • 访问权限:委托可在外部任意赋值、清空、调用;事件只能在类内部触发,外部只能订阅/取消订阅
  • 安全性:事件更安全,避免外部篡改委托列表
  • 使用场景:内部逻辑回调用委托,对外暴露的消息通知用事件

  • 九、全文总结

  • 委托是存储方法的引用类型,实现了方法的传递与延迟调用;
  • 委托是类型安全的,彻底解决函数指针的安全问题;
  • 日常开发优先使用 Action/Func/Predicate 内置委托,配合Lambda简化代码;
  • 委托支持多播、回调、解耦,是事件、LINQ、异步编程的底层基础;
  • 开发中优先用事件对外暴露,委托仅用于内部逻辑处理。

  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【C#零基础进阶】委托(Delegate)超详细精讲,从原理到实战全覆盖
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!