云在青天部落阁

独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
扩大
缩小

C#的事件与委托

目录

  • 事件概念:

      事件概念(Event):所谓的事件是指用户的操作,或者是一些提示信息等等。应用程序需要在事件发生时响应事件。C#中使用事件机制实现线程间的通信。
    
  • 通过事件使用委托相关概念:

      事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。
      发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。
      订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。
    
  • [声明事件:]

      在类的内部声明事件,首先必须声明该事件的委托类型,e.gpublic delegate void BoilerLogHandler(string status);然后,声明事件本身,使用 event 关键字,
      // 基于上面的委托定义事件
    public event BoilerLogHandler BoilerEventLog;
    上面的代码定义了一个名为 BoilerLogHandler 的委托和一个名为 BoilerEventLog 的事件,该事件在生成的时候会调用委托,委托调用订阅器里面的方法(事件处理程序处理事件)。
    
  • [插入一个小片段----Virtual(虚方法):]

    virtual关键字用于在基类中修饰方法。virtual的使用会有两种情况:
    情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。
    情况2:在基类中定义了virtual方法,然后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。
      代码示例一:
      using System;
      namespace SimpleEvent
      {
      	/***********发布器类***********/
    public class EventTest
    {
      private int value;
    
      public delegate void NumManipulationHandler();
    
      public event NumManipulationHandler ChangeNum;
      protected virtual void OnNumChanged()
      {
        if ( ChangeNum != null )
        {
          ChangeNum(); /* 事件被触发 */
        }else {
          Console.WriteLine( "event not fire" );
          Console.ReadKey(); /* 回车继续 */
        }
      }
    
      public EventTest()
      {
        int n = 5;
        SetValue( n );
      }
    
    
      public void SetValue( int n )
      {
        if ( value != n )
        {
          value = n;
          OnNumChanged();
        }
      }
    }
    
    
    /***********订阅器类***********/
    
    public class subscribEvent
    {
      public void printf()
      {
        Console.WriteLine( "event fire" );
        Console.ReadKey(); /* 回车继续 */
      }
    }
    
    /***********触发***********/
    public class MainClass
    {
      public static void Main()
      {
        EventTest e = new EventTest(); /* 实例化对象,第一次没有触发事件 */
        subscribEvent v = new subscribEvent(); /* 实例化对象 */
        e.ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* 注册 */
        e.SetValue( 7 );
        e.SetValue( 11 );
      }
    }}
    
  • [代码解析与延伸:]

      e.g:ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* 注册 */
      解析1:-->这里就是简单的给事件赋值操作而已;new EventTest.NumManipulationHandler( v.printf )-->事件的处理程序通过委托去调用;老的C#版本中会这样去调用,在如今的C#版本中,使用的是直接把事件处理方法赋值给事件--e.g ChangeNum = v.printf ;此外,还有一个点要注意,把方法传给委托时,方法的参数列表和返回值类型和委托的一致才可以。
      e.g:public event NumManipulationHandler ChangeNum;
      延伸1:event NumManipulationHandler可理解为一种类型,在C#新发布的版本中,可以用Action来代替传统的委托声明方式,e.g:public delegate int NumManipulationHandler();等效于public Action ChangeNum;
      延伸2.以前为了能调用一个方法,必须定义一个相应的delegate,后来便有了通用委托Func<>,方便多了。没有参数: Func<TResult>;有参数:Func<T,TResult>,T代表传入参数类型,TResult代表返回参数类型,当然可以有多个参数T1、T2、T3…
      延伸3.Action<T>的用法与Func几乎一样,调用方法也类似,两者都支持Lambda表达式。
      延伸4:Func与Action的区别
      Func与Action作用几乎一样。只是Func<Result>有返回类型;Action<T>只有参数类型,不能传返回类型。所以Action<T>的委托函数都是没有返回值的。
    

posted on 2019-07-26 19:43  NoMatterTryAgain  阅读(304)  评论(0编辑  收藏  举报

导航