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

 更新时间:2022年09月09日 14:08:35   作者:云无极  
这篇文章主要介绍了C#中委托、事件和回调的使用及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用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");
        }

执行的结果

利用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");
        }

带参数的事件案例

参考网上的案例,场景:首领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");
        }

运行效果

回调函数的使用案例

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

        //实际开发中,下面这个类会封装起来,只提供函数接口。相当于系统底层
        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");
        }

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

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

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

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

相关文章

  • C# 结合 Javascript 测试获取天气信息

    C# 结合 Javascript 测试获取天气信息

    本文将介绍如何使用 C# 并结合 JavaScript 获取天气信息,获取的数据来源于360浏览器首页数据,对C# 获取天气信息示例代码感兴趣的朋友一起看看吧
    2024-08-08
  • 常用C#正则表达式汇总介绍

    常用C#正则表达式汇总介绍

    c#正则表达式,用于字符串处理、表单验证等场合,实用高效。现将一些常用的表达式收集于此,以备不时之需。
    2016-01-01
  • 在Linux上运行C#的方法

    在Linux上运行C#的方法

    这篇文章主要介绍了在Linux上运行C#的方法,实例分析了Linux平台下Mono软件包的应用技巧,以及在此基础之上的C#运行方法,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-12-12
  • 10分钟学会Visual Studio将自己创建的类库打包到NuGet进行引用(net,net core,C#)

    10分钟学会Visual Studio将自己创建的类库打包到NuGet进行引用(net,net core,C#)

    这篇文章主要介绍了10分钟学会Visual Studio将自己创建的类库打包到NuGet进行引用(net,net core,C#),本文给大家介绍的非常详细对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • C# WCF简单入门图文教程(VS2010版)

    C# WCF简单入门图文教程(VS2010版)

    这篇文章主要介绍了WCF简单入门图文教程,版本是VS2010版,帮助大家轻松学习了解DataContract、ServiceContract等特性,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • C#编程中最容易犯的7种编写错误分享

    C#编程中最容易犯的7种编写错误分享

    编程时犯错是必然的,这篇文章主要和大家来分享7个C#编程中最容易犯的7种编写错误,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2023-03-03
  • 在C#项目中调用C++编写的动态库的三种方式

    在C#项目中调用C++编写的动态库的三种方式

    这篇文章给大家介绍了三种方式详解如何在C#项目中调用C++编写的动态库,文中通过代码示例给大家介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2024-01-01
  • C#实现简单成绩管理系统的完整步骤

    C#实现简单成绩管理系统的完整步骤

    这篇文章主要给大家介绍了关于C#实现简单成绩管理系统的完整步骤,文中通过示例代码介绍的非常详细,对大家的学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-11-11
  • C#实现appSettings节点读取与修改的方法

    C#实现appSettings节点读取与修改的方法

    这篇文章主要介绍了C#实现appSettings节点读取与修改的方法,是非常实用的技巧,需要的朋友可以参考下
    2014-10-10
  • c#添加图片、文本水印到PDF文件

    c#添加图片、文本水印到PDF文件

    这篇文章主要介绍了如何用c#给PDF文件添加文本、图片水印,文中代码非常详细供大家学习参考,感兴趣的朋友可以了解下
    2020-06-06

最新评论