• C#-委托的详细用法


    什么是委托

    委托是一种函数引用的Object,实际上是用类完成了函数指针的功能

    C#中的委托(Delegate)类似于C或C++中函数的指针。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。

    委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生 自System.Delegate 类。

    委托的使用

    1,声明委托:

    Delegate void Print(int x)

    2,初始化,给委托赋值

    • 方法1:Print someFunc=hello;
    • 方法2:Print someFunc=new Print(hello);

    3,调用委托变量

    SomeFunc(x);

    委托的分类

    • 委托静态方法:委托一个静态方法
    • 委托实例方法:委托一个实例方法

    委托的原理

    委托是将函数指针和实例对象打包在一起的类,它有两个重要的成员,一个用来保存实例对象,一个用来保存函数的指针。从源码中可以查看System.Delegate

     我们查看System.Delegate的属性,可以看到一个属性Target

    1. public Object Target
    2. {
    3. get
    4. {
    5. return GetTarget();
    6. }
    7. }

    看一下GetTarget的功能

    1. internal virtual Object GetTarget()
    2. {
    3. return (_methodPtrAux.IsNull())?_target:null;
    4. }

    意思就是当把一个静态方法给委托的时候将会返回一个null,如果是一个实例方法时, 将会返回当前方法所在的实例对象(this)

    下面用一段代码演示一下:

    1. using System;
    2. //声明委托
    3. public delegate void Print(int x);
    4. namespace ConsoleApp1
    5. {
    6. public class Test
    7. {
    8. //实例方法
    9. public void Test1(int x)
    10. {
    11. Console.WriteLine("实例方法,数字:{0}",x);
    12. }
    13. //静态方法
    14. public static void Test2(int x)
    15. {
    16. Console.WriteLine("静态方法,数字:{0}",x);
    17. }
    18. }
    19. class Program
    20. {
    21. static void Main(string[] args)
    22. {
    23. //委托的使用
    24. Test t = new Test();//实例对象
    25. Print p1 = new Print(t.Test1);//委托赋值
    26. p1(25);//调用委托
    27. Print p2 = Test.Test2;//委托赋值
    28. p2(33);//调用委托
    29. //委托原理
    30. Console.WriteLine(p1.Target is Test);//实例方法-判断Target是不是指向方法所在的对象
    31. Console.WriteLine(p2.Target is Test);//静态方法-判断Target是不是null
    32. Console.ReadLine();
    33. }
    34. }
    35. }

    输出结果

    1. 实例方法,数字:25
    2. 静态方法,数字:33
    3. True
    4. False

    也就是如果Target属性为null说明是静态方法的委托,如果不为null说明是实例方法的 委托

    需要注意的是声明的委托类型和被委托的函数类型以及参数要一致,如果委托没有返回 值,那么被委托的函数也要没有返回值,如果委托有参数,那么被委托的函数和委托的 参数类型要一致。

    通过这个代码就可以很直白的看出委托的作用,就是将方法封装在委托中,然后就可以将委托对象传递给可调用所引用方法的代码,不必在编译时知道将要调用那个方法。

    系统内置委托

    前面是自己定义的委托,但是系统也提供了两种委托:Action和Func,Action用于不需 要返回值的委托,Func适合需要返回值的委托

    Action委托

    1,Action委托 封装一个方法,该方法不具有参数并且不返回值

    2,Action委托 封装一个方法,该方法只有一个参数并且不返回值

    3,Action委托 封装一个方法,该方法具有两个参数并且不返回值

    最多有16个参数

    Func委托

    1,Func(TResult)委托封装封装一个不具有参数但却返回 TResult 参数指定的类型值的方 法

    2,Func(T,TResult)委托 封装一个具有一个参数并返回 TResult 参数指定的类型值的方法

    3,Func(T1,T2,TResult)委托 封装一个具有两个参数并返回 TResult 参数指定的类型值的方 法

    其中的T是参数类型,TResult是返回值类型

    下面用一个例子演示:

    1. using System;
    2. namespace ConsoleApp1
    3. {
    4. public class Test
    5. {
    6. //Action示例
    7. public void Test1(int x)
    8. {
    9. Console.WriteLine("打印数字:"+x);
    10. }
    11. //Func示例
    12. public int Test2(int n)
    13. {
    14. return n;
    15. }
    16. }
    17. class Program
    18. {
    19. static void Main(string[] args)
    20. {
    21. //系统内置委托的使用
    22. Test t = new Test();//实例对象
    23. Action<int> ac1 = new Action<int>(t.Test1);//委托赋值
    24. ac1(22);//调用委托
    25. Func<int, int> ac2 = new Func<int, int>(t.Test2);//委托赋值
    26. Console.WriteLine(ac2(233));//调用委托
    27. Console.ReadLine();
    28. }
    29. }
    30. }

    输出结果:

    1. 打印数字:22
    2. 233

    多播委托

    多播委托是指在一个委托中注册多个方法,在注册方法时可以在委托中使用加号运算符

    或者减号运算符来实现添加或撤销方法。

    比如现实的点餐系统,可以点甜食,面食,水果等,在这里委托相当于点餐平台,每一 个类型的商品可以理解为在委托商注册的一个方法。

    使用委托的这个有用的特点,可以创建一个委托被调用时要调用的方法的调用列表。 这被称为委托的 多播(multicasting),也叫组播。

    下面的程序演示了委托的多播:

    1. using System;
    2. //声明委托
    3. public delegate void Order();
    4. namespace ConsoleApp1
    5. {
    6. public class Test
    7. {
    8. //买水果
    9. public void Test1()
    10. {
    11. Console.WriteLine("购买水果!");
    12. }
    13. //买甜食
    14. public static void Test2()
    15. {
    16. Console.WriteLine("购买甜食!");
    17. }
    18. }
    19. class Program
    20. {
    21. static void Main(string[] args)
    22. {
    23. //多播委托
    24. Test t = new Test();//实例对象
    25. Order order =new Order(t.Test1);//委托赋值-实例方法
    26. order += new Order(Test.Test2);//委托赋值-静态方法
    27. order();//调用委托
    28. Console.ReadLine();
    29. }
    30. }
    31. }

    输出结果:

    1. 购买水果!
    2. 购买甜食!

    通过这个例子可以看出来,我们把两个方法都注册到了一个委托上面,并且调用委托一 下调用了两个方法,先调用了购买水果的方法,然后调用了购买甜食的方法。

    在使用多播委托时需要注意,在委托中注册的方法参数列表必须与委托定义的参数列表 相同,否则不能将方法添加到委托上。

    如有错漏之处,敬请指正!

  • 相关阅读:
    【数据结构初阶】初始二叉树 -- (二叉树基础概念+二叉树的顺序结构及实现)
    mysql XA 分布式事务
    查询附近500米的餐厅
    NoSQL
    基于Matlab-gui信号系统设计
    什么是城市坐标系,与国家坐标系的区别?
    OLED透明屏的制造过程是怎样的?
    IoC控制反转
    手机云便签待办分类内容怎么排序?
    【记录文】Android自定义Dialog实现圆角对话框
  • 原文地址:https://blog.csdn.net/qq_52905520/article/details/126261862