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++中的方法指针。而与委托相应的事件则为委托提供了封闭。

  • 相关阅读:
    HDU 5744
    HDU 5815
    POJ 1269
    HDU 5742
    HDU 4609
    fzu 1150 Farmer Bill's Problem
    fzu 1002 HangOver
    fzu 1001 Duplicate Pair
    fzu 1150 Farmer Bill's Problem
    fzu 1182 Argus 优先队列
  • 原文地址:https://www.cnblogs.com/mane/p/2039644.html
Copyright © 2011-2022 走看看