zoukankan      html  css  js  c++  java
  • 浅谈c#中的委托和事件

          大学扩招后,各类大学或学院如牛毛般兴起。随之而产生的现象是大学生源质量的下降,而优质大学老师也是僧多粥少,必然使大量水平尚不达标的教师混入各类院校,使上课的精彩程度有所降低。于是,逃课的学生们也越来越多...

          作为众多大学生中一员的本文作者,也混迹在某所二流学校里。

          某天上课铃响后,授课老师拿着《管理信息系统》一书讲课到一半,眼睛一描台下寥寥无几昏昏欲睡的几个“好”学生,脸上泛起阴沉的笑容,”我们来点名吧!没到的举手!“这话乍一出口,台下便一片大乱,美女班长急匆匆拿起手机,快速按着键盘编辑短信催逃课的同学来上课。

          本文的作者作为当时在场的一员,目睹当今大学课堂之怪状,脑中立即浮现出本程序的雏形。

          首先,我们分别以三个类Teacher,Monitor,Student表示教师,班长,逃课同学,其中教师有一个点名方法,班长有个发短信通知逃课同学来上课的方法,逃课同学则有个方法表示回复班长短信通知。

          接着,我们在Teacher类中定义一个委托和与之对应的事件,分别如下:

    public delegate void signHandler(bool param);
    public event signHandler sign;

         再为Teacher类添加一个私有变量,该变量用以指示教师是否已点名。

    private bool isSigned;

         最后是为Teacher类增加一个点名方法,方法的具体实现请看代码

    public void SignName()
    {
      Console.WriteLine(
    "我是老师:不来上课?后果很严重!");
      
    this.isSigned =true;
      
    //触发点名事件
      if (sign !=null)
      {
        sign(isSigned);
      }
    }

         至此,Teacher类全部完成。而代表班长的Monitor类与Teacher类非常类似,它有一个sendHandler委托,和封装该委托的表示发通知短信的send事件。最后Monitor类还有一个SendSMS方法,它表示班长发通知短信的动作。具体实现参见代码

    class Monitor
    {
      
    public delegate void sendHandler(bool param);
      
    public event sendHandler send;
      
    //表示班长是否已发通知短信的私有字段
      private bool isSent;
      
    //班长看到教师点名后发短信通知没来同学
      public void SendSMS(bool param)
      {
        
    if (param)
        {
          Console.WriteLine(
    "我是班长:老师点名了,快来上课,不来期末不给过!");
          
    this.isSent =true;
          
    //触发发短信事件
          if (send !=null)
          {
            send(isSent);
          }
        }
      }
    }

         到此为止,大部分工作都已完成。最后出场的是表示逃课学生的Student类,该类实现非常简单,只有一个GoToClass方法,表示该学生收到班长通知短信后回复短信并赶去课室。

    class Student
    {
      
    //学生收到班长短信后去上课
      public void GoToClass(bool param)
      {
        
    if (param)
        {
          Console.WriteLine(
    "我是学生:报告班长,短信已收到,正赶来上课!");
        }
      }
    }

          最后,我们来看下主程序如何实现。先分别构造教师,班长,学生的实例,再将Monitor类的SendSMS方法注册到Teacher类的sign事件上,这样做表示了班长的发短信方法订阅了教师的方法,教师一点名即触发sign事件,此时班长立刻会心的传短信通知未到学生来上课。

          接着我们还要将逃课学生的GoToClass方法注册到班长的send事件上,班长发短信表示教师点名了,逃课学生只得乖乖的赶去上课,学分为大嘛。

    class Program
    {
      
    static void Main(string[] args)
      {
        Teacher teacher
    =new Teacher();
        Monitor monitor
    =new Monitor();
        Student student
    =new Student();
        
    //班长的发短信方法订阅教师的点名事件
        teacher.sign +=new Teacher.signHandler(monitor.SendSMS);
        
    //学生的上课方法订阅班长的发短信事件
        monitor.send +=new Monitor.sendHandler(student.GoToClass);
        teacher.SignName();
      }
    }
     
    完整版DEMO如下:
    namespace delegateDEMO
    {
      
    class Teacher
      {
        
    public delegate void signHandler(bool param);
        
    public event signHandler sign;
        
    //表示教师是否已点名的私有字段
        private bool isSigned;
        
    //教师点名
        public void SignName()
        {
          Console.WriteLine(
    "我是老师:不来上课?后果很严重!");
          
    this.isSigned =true;
          
    //触发点名事件
          if (sign !=null)
          {
            sign(isSigned);
          }
        }
      }

      
    class Monitor
      {
        
    public delegate void sendHandler(bool param);
        
    public event sendHandler send;
        
    //表示班长是否已发通知短信的私有字段
        private bool isSent;
        
    //班长看到教师点名后发短信通知没来同学
        public void SendSMS(bool param)
        {
          
    if (param)
          {
            Console.WriteLine(
    "我是班长:老师点名了,快来上课,不来期末不给过!");
            
    this.isSent =true;
            
    //触发发短信事件
            if (send !=null)
            {
              send(isSent);
            }
          }
        }
      }

      
    class Student
      {
        
    //学生收到班长短信后去上课
        public void GoToClass(bool param)
        {
          
    if (param)
          {
            Console.WriteLine(
    "我是学生:报告班长,短信已收到,正赶来上课!");
          }
        }
      }

      
    class Program
      {
        
    static void Main(string[] args)
        {
          Teacher teacher
    =new Teacher();
          Monitor monitor
    =new Monitor();
          Student student
    =new Student();
          
    //班长的发短信方法订阅教师的点名事件
          teacher.sign +=new Teacher.signHandler(monitor.SendSMS);
          
    //学生的上课方法订阅班长的发短信事件
          monitor.send +=new Monitor.sendHandler(student.GoToClass);
          teacher.SignName();
        }
      }
    }

        程序运行的结果如下:

         写在最后:也许有的朋友看完上面的例子后,会觉得程序中的委托和事件形式与webform和winform中的形式有很大区别,比如winform中常见的按钮单击,其委托和事件的定义分别如下

    public delegate void EventHandler(object sender, EventArgs e);
    public event EventHandler Click;

         而我们在界面上双击按钮后,进入后台代码中的Click方法如下

    private void button1_Click(object sender, EventArgs e)
    {
      MessageBox.Show(
    "Hello World!");
    }

         由此我们可以得知.net framework中委托和事件的编码规范有以下几条:

    • 委托类型名称以EventHandler结束。
    • 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object类型,表示事件源,一个EventArgs类型(或继承自EventArgs),表示事件参数。
    • 事件类型名称为委托去掉EventHandler之后剩余的部分。
    • 继承自EventArgs的类型应该以EventArgs结尾。
    • 订阅事件的方法的命名,通常为“On+事件名”

        知道规范后,我们再来看看根据该规范对上述程序的修改

    namespace NormalizeDelegateDemo
    {
      
    public class Teacher
      {
        
    public delegate void SignEventHandler(object sender, SignEventArgs e);
        
    public event SignEventHandler Sign;
        
    //表示教师是否已点名的私有字段
        private bool isSigned;
        
    public class SignEventArgs : EventArgs
        {
          
    public readonly bool isSigned;
          
    public SignEventArgs(bool issigned)
          {
            
    this.isSigned = issigned;
          }
        }
        
    public void OnSign(SignEventArgs e)
        {
          
    if (Sign !=null)
          {
            Sign(
    this, e);
          }
        }
        
    //教师点名
        public void SignName()
        {
          Console.WriteLine(
    "我是老师:不来上课?后果很严重!");
          
    this.isSigned=true;
          
    //触发点名事件
          SignEventArgs e =new SignEventArgs(isSigned);
          OnSign(e);
        }
      }

      
    public class Monitor
      {
        
    public delegate void SendEventHandler(object sender,SendEventArgs e);
        
    public event SendEventHandler Send;
        
    //表示班长是否已发通知短信的私有字段
        private bool isSent;
        
    public class SendEventArgs : EventArgs
        {
          
    public readonly bool isSent;
          
    public SendEventArgs(bool issent)
          {
            
    this.isSent = issent;
          }
        }
        
    public void OnSend(SendEventArgs e)
        {
          
    if(Send!=null)
          {
            Send(
    this,e);
          }
        }
        
    //班长看到教师点名后发短信通知没来同学
        public void SendSMS(object sender,Teacher.SignEventArgs e)
        {
          
    if (e.isSigned)
          {
            Console.WriteLine(
    "我是班长:老师点名了,快来上课,不来期末不给过!");
            
    this.isSent =true;
            
    //触发发短信事件
            SendEventArgs _e =new SendEventArgs(isSent);
            OnSend(_e);
          }
        }
      }

      
    public class Student
      {
        
    //学生收到班长短信后去上课
        public void GoToClass(object sender,Monitor.SendEventArgs e)
        {
          
    if (e.isSent)
          {
            Console.WriteLine(
    "我是学生:报告班长,短信已收到,正赶来上课!");
          }
        }
      }

      
    public class Program
      {
        
    static void Main(string[] args)
        {
          Teacher teacher
    =new Teacher();
          Monitor monitor
    =new Monitor();
          Student student
    =new Student();
          
    //班长的发短信方法订阅教师的点名事件
          teacher.Sign +=new Teacher.SignEventHandler(monitor.SendSMS);
          
    //学生的上课方法订阅班长的发短信事件
          monitor.Send +=new Monitor.SendEventHandler(student.GoToClass);
          teacher.SignName();
        }
      }
    }

         好了,整篇文章也到了结束的时候。最后我们再来回顾下结论:链接到委托上的方法必须具有与委托相同的方法签名,委托可以代表一类特定方法签名的方法,它的功能类似于C++中的方法指针。而与委托相应的事件则为委托提供了封闭与包装。

     
    作者: caochao
    邮箱: caochao88@gmail.com
    出处: http://www.cnblogs.com/tudas
    本文版权归作者和博客园共有,欢迎转载,未经作者同意须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    如果您觉得本文的内容对您的学习有所帮助: 捐助共勉
  • 相关阅读:
    React组件-初识React1(慕课)
    高德地图
    js 格式化数字,数字每隔三位加个逗号
    css样式(格子、液晶字体)
    Echart
    css 渐变
    RAP的使用方法
    重新排序数组中的对象(根据对象中的某个属性来排列)
    EF context.SaveChanges()特点
    EF 导航属性的使用
  • 原文地址:https://www.cnblogs.com/tudas/p/delegate.html
Copyright © 2011-2022 走看看