C# 委托和事件 (三)

委托

在C#中,委托(delegate)是一种引用类型,在其他语言中,与委托最接近的是函数指针,但委托不仅存储对方法入口点的引用,还存储对用于调用方法的对象实例的引用。

using System;
using System.IO;

namespace DelegateAppl
{
   class PrintString
   {
      static FileStream fs;
      static StreamWriter sw;
      // 委托声明
      public delegate void printString(string s);

      // 该方法打印到控制台
      public static void WriteToScreen(string str)
      {
         Console.WriteLine("The String is: {0}", str);
      }
      // 该方法打印到文件
      public static void WriteToFile(string s)
      {
         fs = new FileStream("c:\\message.txt", FileMode.Append, FileAccess.Write);
         sw = new StreamWriter(fs);
         sw.WriteLine(s);
         sw.Flush();
         sw.Close();
         fs.Close();
      }
      // 该方法把委托作为参数,并使用它调用方法
      public static void sendString(printString ps)
      {
         ps("Hello World");
      }
      static void Main(string[] args)
      {
         printString ps1 = new printString(WriteToScreen);
         printString ps2 = new printString(WriteToFile);
         sendString(ps1);
         sendString(ps2);
         Console.ReadKey();
      }
   }
}

使用方法:

delegate <return type> <delegate-name> <parameter list>

像是类一样进行声明。

printString ps1 = new printString(WriteToScreen)

在上述代码中,委托进行实例化。

sendString(ps1);

委托的实例化对象像是参数一样传入到函数之中。

ps("Hello World");

实现委托中封装的方法。

为什么要使用委托?

我理解的用途感觉和多态的动态链接有些相似,我不知道我可能选择用哪种方法实现。在多态当中,是不确定对象的实际类别。

比如上述代码,在**sendString()**中首先明确我是要对“Hello World进行操作哦”, 但是我可能有多种对于"Hello world的方法"。可能是打印在屏幕上,可能是打印在文件里面。

试着想一下,如果我们都在一个函数当中实现这些功能,我们要在传入参数的时候,用一个简单的标记告诉要实现哪种方法,然后使用if,else语句进行实现,和case的感觉有一些像。

首先上述的实现方法,将功能都做到一个函数之中,不具有可拓展性,不易于理解,其次如果每个方法有非常复杂的代码,那么我们最好将其封装到一个函数当中。

通俗理解,我们将我们的函数封装成了一个参数,进入其他的函数实现委托封装的功能。看上去我们像是一个大功能由多个小功能组成,但是注意的是,委托的声明有指定类型,我们在调用委托的时候只能对它声明时候限定的类型进行操作。

比如一只龙虾,你有刺身,清蒸,烘烤三种吃法,吃法是委托,三种吃法都是委托的实例化。但是他们都是对于龙虾的操作,所以在食用函数中,以一种吃法作为参数传递,然后将龙虾作为吃法的参数。

所以和我们最开始所说的,它是对方法的引用,同时也是对实例化的引用。

委托的另一个比较的用途在下面的事件介绍。

事件

由于平时很少做开发,但我做过小程序,事件应该是类似于button,点击的话调用相关的函数。

事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些提示信息,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。

C# 中使用事件机制实现线程间的通信。

using System;
namespace SimpleEvent
{
  using System;
  /***********发布器类***********/
  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 );
    }
  }
}

我们先脱离代码,想一下,如果定义一个事件需要哪些内容。

首先我们要知道谁使用这个事件,所以需要有订阅器,即使用对象。事件是需要行为触发的,不同的行为对应着不同的响应方法,所以我们首先要知道是谁的行为。这个被称之为发布器。事件建立在委托的基础上。

订阅器:我们还需要知道,需要什么处理方法,事件属于回调函数。

为什么发布器需要委托呢?我们回忆一下我,委托是将类的方法封装起来并且还可以实例化。我们事件的响应是需要根据触发的条件,比如一个button,是点击了一下,还是点击了两下,或者三下,都对应不同的方法,这非常适合符合委托的使用请况。

使用委托的另一个好处就是,委托可以看作一种类型,类型后面跟的是声明的事件,订阅器在注册的时候,即对应事件的某个触发,肯定是要对应的发布器和对应的订阅器相互响应,如果把委托看成一种类型,可以很好的进行约束。

比如发布事件在a类,(事件要发布在类中)订阅在b类,那么在c类中定义:
实例a = delegate (b.方法)。所以订阅器就是实现的方法,发布就是一个响应的接口。发布器是委托,响应的接口符合了委托的概念,往里面填充函数。

基于以上理解,可以试着理解一下上面的代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值