C#中委托、事件和回调的使用及说明

作者:云无极 时间:2023-08-13 01:00:24 

委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。

事件是对委托的封装。如果不进行封装,让委托暴露给调用者,调用者就可以把委托变量重新引用到新的委托对象,也就删除了当前要调用的方法列表;

定义一个事件有两步,首先定义一个委托,它包括了这件事的“协议”和委托方法(由谁去做);其次,用event关键字和相关委托声明这个事件。事件像是一个接口,封装了委托所定的“协议”。由于委托已经定义了协议,剩下的就是按这个协议去办事,至于怎么做它并不关心。调用者无法访问委托对象。

回调函数就是把一个方法的传给另外一个方法去执行。回调函数只是一个功能片段,由用户按照回调函数的调用约定来实现的一个函数。可以把任意一个符合这个委托的方法传递进去,意思就是说这部分代码是可变的。而设计上有一个抽离出可变部分代码的原则,这种用法无疑可以用到那种场合了。从上可知,事件和回调都是对委托的一种用法。事件是把委托封装起来,而回调函数则是由委托绑定不同的函数来实现不同的功能。

委托的使用案例

定义委托和方法

//委托定义(要与方法中参数一致)
       public delegate int DelegateTest(int n1, int n2);

class Math
       {
           //方法定义(委托要执行的方法,本案例把方案写到class类中)
           public int Multiply(int n1, int n2)
           {
               return n1 * n2;
           }

public int AddTest(int n1, int n2)
           {
               return n1 + n2;
           }
       }

委托的使用

private void button1_Click(object sender, EventArgs e)
       {
           Math objMath = new Math();

//创建委托对象
           DelegateTest delegateDemo1;

//将方法与委托对象关联起来 (委托:将方法当作另一个方法的参数来进行传递)
           //delegateDemo1 = new CallDelegate(objMath.Multiply);
           delegateDemo1 = objMath.Multiply; //与上面方法相同
           //delegateDemo1 += objMath.AddTest;  //给委托对象再绑定一个方法,若该条代码执行,显示结果为17

//将委托实例化
           int result = delegateDemo1(5, 12);
           richTextBox1.AppendText(result.ToString() + "\r");

//****委托的另外一写法,通过Action或Func,如果有返回值用Func,否则用Action *****//
           //Func<int, int, int> func1 = new Func<int, int, int>(objMath.Multiply);
           Func<int, int, int> func1 = objMath.Multiply;
           richTextBox1.AppendText(func1.Invoke(6, 13) + "\r");
       }

执行的结果

C#中委托、事件和回调的使用及说明

利用Action或Func简化代码

private void button4_Click(object sender, EventArgs e)
       {
           Math objMath = new Math();
           //委托的另外一写法,通过Action或Func,如果有返回值用Func,否则用Action
           //Func<int, int, int> func1 = new Func<int, int, int>(objMath.Multiply); //同下
           Func<int, int, int> func1 = objMath.Multiply;
           richTextBox1.AppendText(func1.Invoke(6, 13) + "\r");
       }

事件的使用案例

class ClassA
       {
           public string ClassAinfo = "A 默认!";
           public void DispInfo()
           {
               ClassAinfo = "A 收到!";
           }
       }

class ClassB
       {
           public string ClassAinfo = "B 默认!";
           public void DispInfo()
           {
               ClassAinfo = "B 收到!";
           }
       }
       class DelegatEventTest
       {
           //定义委托
           public delegate void MyDelegateEventHandler();
           //定义事件
           public event MyDelegateEventHandler NotifyEveryOne;
           //调用事件
           public void Notify()
           {
               if (NotifyEveryOne != null)
               {
                   NotifyEveryOne();
               }
           }
       }

事件的使用

private void button3_Click(object sender, EventArgs e)
       {
           //创建classA和classB的对象
           ClassA objA = new ClassA();
           ClassB objB = new ClassB();
           //创建委托的对象
           DelegatEventTest event1 = new DelegatEventTest();

//订阅事件(类似于 方法与委托事件的关联)
           event1.NotifyEveryOne += new DelegatEventTest.MyDelegateEventHandler(objA.DispInfo);
           //event1.NotifyEveryOne += new DelegatEventTest.MyDelegateEventHandler(objB.DispInfo);

event1.Notify();

richTextBox1.AppendText(objA.ClassAinfo + "\r");
           richTextBox1.AppendText(objB.ClassAinfo + "\r");
       }

C#中委托、事件和回调的使用及说明

带参数的事件案例

参考网上的案例,场景:首领boyK要搞一场鸿门宴,吩咐部下boyA和boyB各自带队埋伏在屏风两侧,约定以杯为令:若左手举杯,则boyA带队杀出;若右手举杯,则boyB带队杀出;若直接摔杯,则boyA和boyB同时杀出。boyA和boyB袭击的具体方法,首领boyK并不关心。

boyK的定义

public class BoyK
       {
           //定义委托
           public delegate void RaiseEventHandler(string hand);
           public delegate void FallEventHandler();

//定义事件
           public event RaiseEventHandler RaiseEvent;
           public event FallEventHandler FallEvent;

//调用事件(例:举手事件)
           public void Raise(string hand)
           {
               if (RaiseEvent!=null)
               {
                   RaiseEvent(hand);
               }
           }
           //调用事件(例:摔杯事件)
           public void Fall()
           {
               if (FallEvent!=null)
               {
                   FallEvent();
               }
           }            
       }

boyA的定义

class BoyA
       {
           public string str = "A待命";
           BoyK boyk;
           public BoyA(BoyK k)
           {
               boyk = k;
               k.RaiseEvent += new BoyK.RaiseEventHandler(k_RaiseEvent);   //订阅举杯事件
               k.FallEvent += new BoyK.FallEventHandler(k_FallEvent);      //订阅摔杯事件
           }
           public void Attack()
           {
               str = "A开始**";
           }

//boyK举杯的动作
           void k_RaiseEvent(string hand)
           {
               if (hand.Equals("左"))
               {
                   Attack();
               }
           }

void k_FallEvent()
           {
               Attack();
           }        
       }

boyB的定义

class BoyB
       {
           public string str = "B待命";
           BoyK boyk;
           public BoyB(BoyK k)
           {
               boyk = k;
               k.RaiseEvent += new BoyK.RaiseEventHandler(k_RaiseEvent);   //订阅举杯事件
               k.FallEvent += new BoyK.FallEventHandler(k_FallEvent);      //订阅摔杯事件
           }

public void Attack()
           {
               str = "B开始**";
           }

void k_RaiseEvent(string hand)
           {
               if (hand.Equals("右"))
               {
                   Attack();
               }
           }

void k_FallEvent()
           {
               Attack();
           }
       }

事件的使用

private void button2_Click(object sender, EventArgs e)
       {
           BoyK boyK = new BoyK();
           BoyA boyA = new BoyA(boyK);
           BoyB boyB = new BoyB(boyK);

//boyK.Raise("左");
           boyK.Raise("右");
           //boyK.Fall();

richTextBox1.AppendText(boyA.str+"\r");
           richTextBox1.AppendText(boyB.str + "\r");
       }

运行效果

C#中委托、事件和回调的使用及说明

回调函数的使用案例

实际开发中,下面这个类会封装起来,只提供函数接口。相当于系统底层

//实际开发中,下面这个类会封装起来,只提供函数接口。相当于系统底层
       class CalculateClass
       {
           public delegate int SomeCalculateWay(int num1, int num2);
           //将传入参数在系统底层进行某种处理,具体计算方法由开发者开发,函数仅提供执行计算方法后的返回值
           //下面的代码中相当于调用了一个回调函数
           public int Calculate(int num1, int num2, SomeCalculateWay call)
           {
               return call(num1, num2);
           }
       }

开发层处理,开发人员编写具体的计算方法

//开发层处理,开发人员编写具体的计算方法
       class FunctionClass
       {
           public int GetSum(int a, int b)
           {
               return a + b;
           }

public int GetMulti(int a, int b)
           {
               return a * b;
           }
       }

用户层,执行输入等操作

private void button4_Click(object sender, EventArgs e)
       {
           CalculateClass cc = new CalculateClass();
           FunctionClass fc = new FunctionClass();

int result1 = cc.Calculate(2, 3, fc.GetSum);
           int result2 = cc.Calculate(2, 3, fc.GetMulti);

richTextBox1.AppendText(result1 + "\r");
           richTextBox1.AppendText(result2 + "\r");
       }

C#中委托、事件和回调的使用及说明

说明:上述代码中的FunctionClass中的GetSum()和GetMulti()两个函数称为回调函数。

可以看到整个程序中并没有哪个地方通过类似GetSum(1,2)这种形式调用了该函数,只有将其当作另一个函数的参数来进行调用。

如cc.PrintAndCalculate(2, 3, fc.GetSum)。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。 

来源:https://blog.csdn.net/zhigedali/article/details/122928563

标签:C#,委托,事件,回调
0
投稿

猜你喜欢

  • Android简单的利用MediaRecorder进行录音的实例代码

    2023-04-24 03:52:57
  • Java总结篇系列:Java泛型详解

    2023-01-25 03:42:58
  • IntelliJ IDEA Project窗口的一些设置详解

    2023-11-09 04:54:44
  • 如何正确使用Android线程详解

    2021-12-06 19:24:30
  • spring boot中配置hikari连接池属性方式

    2022-11-13 06:06:44
  • java集合中list的用法代码示例

    2023-04-11 23:29:17
  • SpringBoot读写操作yml配置文件方法

    2023-10-11 00:13:03
  • 在 Ubuntu Linux 上安装 Oracle Java 14的方法

    2022-01-01 15:13:52
  • Android仿今日头条APP实现下拉导航选择菜单效果

    2023-09-15 07:21:05
  • 用java在web环境下上传和下载文件的技巧

    2021-06-09 18:17:17
  • 基于Java+SpringBoot+Vue前后端分离实现仓库管理系统

    2023-11-01 04:21:22
  • Android实现网易新闻客户端首页效果

    2023-06-09 02:21:06
  • 深入委托与多播委托的详解

    2023-05-29 07:07:15
  • 浅析C#中数组,ArrayList与List对象的区别

    2022-03-12 00:41:30
  • 用C#的params关键字实现方法形参个数可变示例

    2022-04-14 01:53:16
  • Android 6.0 蓝牙搜索不到设备原因,MIUI权限申请机制方法

    2021-07-31 01:20:06
  • java-spark中各种常用算子的写法示例

    2023-04-28 23:21:01
  • 使用Springboot封装一个自适配的数据单位转换工具类

    2022-06-07 07:12:14
  • Android中GridView插件的使用方法

    2021-07-26 16:46:28
  • android 照相功能的简单实例

    2023-08-08 01:11:55
  • asp之家 软件编程 m.aspxhome.com