zoukankan      html  css  js  c++  java
  • C# 委托和事件 笔记

    参考:C#事件解析 徐洪军

         C#委托,事件理解入门 finesite

        委托与事件代码详解 kein

    上面的几位前辈写的文章都很好,这里只是总结一下。

    一、什么是委托和事件

    委托仅仅是函数指针,它能够引用函数,通过传递地址的机制完成,委托是一个类,对委托实例化时,要提供一个引用函
    数,将它作为构造函数的参数。
    每一个委托都有一个签名,被引用的函数必须和委托有相同的签名。
    Delegate int SomeDelegate(string s,bool b);
    private int SomeFunction(string str,bool bln){..}
    SomeDelegate sd=new SomeDelegate(SomeFunction);
    SomeFunction已经被SomeDelegate注册,如果调用sd,那么SomeFunction也会被调用。
    总之,委托可以理解为函数指针,和函数指针不同的是委托是面向对象的。

    事件简单分为两个部分:事件发生的类和事件接收的类。发生的类就是在这个类里面触发事件,但是它不知道究竟是哪个
    对象或方法会处理这个事件。接收的类有一个处理事件的方法。

    二、使用事件的步骤

    1. 创建一个委托
    2. 将委托与特定的事件关联
    3. 编写事件处理程序
    4. 利用事件处理程序生成一个委托实例
    5. 把委托实例添加到产生事件对象的事件列表中

    A产生事件,事件为a,B接受事件,b处理;当a事件产生后,A通过事件列表中的委托对象将事件通知给B,B接收到一个事
    件通知并调用b来处理。

    public class A
    {
       public delegate void EventHandler(object sender);
       public event EventHandler a;
       public void run()
       {
         a(this);
       }
    }
    
    class B
    {
       private void b(object sender)
       {
         ...
       } 
        public B(A a)
       {
          a.a+=new A.EventHandler(this.b);
       }
    }

    三、事件和委托的关系

    事件是对委托的封装,事件底层靠委托实现。

    事件是委托类型的一个变量,所以必须声明在类的内部,因为事件本来就是一个委托,所以可以将赋给委托的方法赋给事件。
    不管将委托声明为public还是protected,它总是在编译的时候被声明为private。所以,只能在声明事件的类的内部对事件进行"="赋值操作。
    委托封装了两个操作"+="和"-=",这两个操作专门用来在类的客户端注册方法。
    委托在编译的时候会编译成类。

    有了委托为什么还要有事件?
    事件是一种委托链,只能够用+=或者-=,防止之前添加的委托被覆盖。
    如果不想让事件被人在类外面随便操作,必须使用事件来定义。

    四、使用事件和委托的典型例子

    例子一:按键事件

    首先,有几点要说明一下,1.EventArgs是包含事件数据的类的基类,如果事件处理程序需要状态信息,则应用程序必须从此类派生一个类来保存数据。2.object sender的sender 是事件源,表示触发此事件的对象;EventArgs e的e是事件参数,包含该事件相关的信息,比如参数,它用来辅助你处理事件,还可以传递引用,在方法中直接访问类的成员等。

    步骤就是:创建一个事件发生的类,定义委托和事件,里面的某一个动作会触发事件;创建一个接收事件的类,生成一个委托实例,并添加到事件列表中。

    internal class KeyEventArgs:EventArgs
    {
      private char keychar;
      public KeyEventArgs(char keyChar):base()
      {
        this.keyChar=keyChar;
      }
      public char KeyChar
      {
        get
        {
          return keyChar;
        }
      }
    }
    
    internal class KeyInputMointor
    {
    public delegate void KeyDownEventHandler(object sender,KeyEventArgs e);
    public event KeyDownHandler KeyDown;
    
    public void run()
    {
     bool finished=false;
     while(!finished)
     {
      Console.WriteLine("Input a char...");
      string response=Console.ReadLine();
      char responseChar=(response=="")?'':char.ToUpper(response[0]);
      if(responseChar=='X') finished=true;
      else{
       //包含事件的数据
       KeyEventArgs keyEventArgs=new KeyEventArgs(responseChar);
       //触发事件
       KeyDown(this,keyEventArgs);
       }
      }
    }
    
    internal class EventReceiver
    {
      public EventReceiver(KeyInputMonitor monitor)
      {
        //产生一个委托实例,并添加到事件列表中
        monitor.KeyDown+=new KeyInputMonitor.KeyDownHandler(this.onKeyDown);
        private void OnKeyDown(object sender,KeyEventArgs e)
        {
         Console.WriteLine("Capture Key:{0}",e.KeyChar);
        }
    }
    
    public class MainEntryPoint
    {
      public static void Start()
      {
       //事件发送器
       KeyInputMointor monitor=new KeyInputMonitor();
       //事件接收器
       EventReceiver eventReceiver=new EventReceiver(monitor);
       //运行
       monitor.run();
      }
    }

    例子二、热水器烧水事件

    public class Heater
    {
      private int temperature;
      //声明事件和委托
      public delegate void BoiledEventHandler(Object sender,BoiledEventArgs e);
      public event BoiledEventHandler Boiled;
    
      //传递温度数据
      public class BoiledEventArgs:EventArgs
      {
        public readonly int temperture;
        public BoidEventArgs(int temperature)
        {
           this.temperature=temperature;
        }
      }
    
      //可供子类重写
      protected virtual void OnBoiled(BoiledEventArgs e)
      {
        //如果有对象注册,就触发Boiled事件,即调用所有注册对象的方法
        if(Boiled!=null)
        {
          Boiled(this,e);
         }
       }
    
       public void BoilWater()
       {
         for(int i=0;i<100;i++)
         {
            temperature=i;
            if(temperature>95)
            {
              //new一个EventArgs对象并传递给OnBoiled函数
              BoiledEventArgs e=new BoiledEventArgs(temperature);
              OnBoiled(e);
            }
         }
       }
    }
    
    //警报器
    public class Alarm
    {
      public void MakeAlert(Object sender,Heater.BoiledEventArgs e)
      {
         Console.WriteLine("Alarm: the temperature now is {0} ",e.temperature);
      }
    }
    
    //显示器
    public class Display
    {
      public static void ShowMsg(Object sender,Heater.BoiledEventArgs e)
      {
        Console.WriteLine("Display:the current is {0} temperature",e.temperature);
      }
    }
    
    class Program
    {
      static void Main()
      {
        Heater heater=new Heater();
        Alarm alarm=new Alarm();
       
        //注册方法有很多种
        heater.Boiled+=alarm.MakeAlert;
        heater.Boiled+=(new Alarm()).MakeAlert();//匿名对象
        heater.Boiled+=new Heater.BoiledEventHandler(alarm.MakeAlert);//和第一种一样
        heater.Boiled+=Display.ShowMsg;//静态的方法
        
        heater.BoiledWater();
        Console.ReadKey();
      }
    }

    五、观察者模式

    观察者模式是为了定义对象间的一种一对多的依赖关系。它是一种松耦合的设计模式。
    observer在subject里面注册,subject某事件发生时通知observer,observer采取相应的行动。


    上一节里面热水器烧水的例子中,Heater就是subject,Alarm和Display就是observer。首先Alarm和Display给Heater进行注册,然后水温高于95度时会通知Alarm和Display,它们分别调用MakeAlarm和ShowMsg方法。

  • 相关阅读:
    半年时间
    deep learning书的阅读
    wgan pytorch,pyvision, py-faster-rcnn等的安装使用
    caffe新版本的各种软件
    你会允许自己家孩子一直不停跟人要东西吗?
    sup inf max min
    leangoo大讲堂—北京站
    使用Leangoo玩转故事地图
    Leangoo:用敏捷开发管理思维做团队协作的SaaS软件
    张江男的逆袭,我如何使用leangoo提升团队效率
  • 原文地址:https://www.cnblogs.com/cubika/p/2768806.html
Copyright © 2011-2022 走看看