C#学习笔记(十一):事件基础

事件类似于异常,因为它们都由对象引发。但是它们也有几个重要的区别:其中最重要的区别就是没有处理异常中try...catch类似的结构来处理事件,而是必须订阅它们。订阅一个事件的含义是提供代码,在事件发生时执行这些代码,它们称为事件处理程序。
事件处理程序本身都是简单的函数。对事件处理函数的唯一限制是它必须匹配于事件所要求的签名(返回类型和参数)。这个签名是事件定义的一部分,由一个委托指定
处理过程:
首先,应用程序创建一个可以引发事件的对象 。例如,假定应用程序是一个即时信息传送应用程序,它创建的对象表示一个远程用户的连接。当接收到通过该连接从远程用户传送来的信息时,这个连接对象会引发一个事件。
接着,应用程序订阅事件 。为此,即时消息传送应用程序将定义一个函数,该函数可以与事件指定的委托类型一起使用,把这个函数的一个引用传送给事件,而事件的处理函数可以是另一个对象的方法,假定是表示显示设备的对象,当接收到信息时,该方法将显示即时信息。
引发事件后,就通知订阅器 。当接收到通过连接对象传送过来的即时消息时,就调用显示设备上的事件处理方法。因为我们使用的是一个标准方法,所以引发事件的对象可以通过参数传送任何相关的信息,这样就大大增加了事件的通用性。
看下面这个例子:
using System;
using System.Timers;
 
namespace Ch12Ex01
{
    /// <summary>
    /// Class1 的摘要说明。
    /// </summary>
    class Class1
    {
        static int counter = 0;
 
        static string displayString = "This string will appear one letter at a time.";
 
        [STAThread]
        static void Main (string[] args)
        {
            Timer myTimer = new Timer(100);
            myTimer.Elapsed += new ElapsedEventHandler(WriteChar);
            myTimer.Start();
            Console.ReadLine();
        }
 
        private static void WriteChar(object sender, ElapsedEventArgs e)
        {
            if(counter>displayString.Length-1)
                return;
            Console.Write(displayString[counter++%displayString.Length]);
        }
    }
}
用于引发事件的对象是 System.Timers.Timer 类的一个实例。使用一个时间段来初始化该对象,当使用Start()方法启动Timer对象时,就引发一系列事件,根据指定的时间段来引发事件。
Timer 对象有一个Elapsed事件,这个事件要求的事件处理程序签名是System.Timers. ElapsedEventHandler委托类型,该委托是在.NET Framework中定义的标准委托之一,用于与下述签名匹配的函数:
void functionName(object sender, ElapsedEventArgs e)
下一个任务是把这个处理程序与事件关联起来――即订阅它。可以使用+=运算符,给事件添加一个处理程序,其形式是用事件处理程序方法初始化的一个新委托实例:
myTimer.Elapsed += new ElapsedEventHandler(functionName)
 
下面是如何定义和使用自己的事件。
在定义事件前,必须先定一个委托类型,以用于该事件,这个委托类型指定了事件处理方法必须遵循的签名
public delegate void MessageHandler(string messageText);
这个委托类型称为MessageHandler,是void函数的签名,它有一个string参数。使用这个参数可以把Connection对象接收过来的即时消息发送给Display对象。
定义了委托后(或者定位现有合适的委托),就可以把事件本身定义为Connection类的一个成员。
    public class Connection
    {
        public event MessageHandler MessageArrived;
给事件命名(这里使用的名称为 MessageArrived ),用 event 关键字和要使用的委托类型(前面定义的 MessageHandler 委托类型)声明它。
以这种方式声明了事件后,就可以引发它,方法是按名称来调用它,就好像它是一个其签名是由委托指定的方法一样。例如使用下面的代码引发这个事件:
MessageArrived("This is a message.");
如果定义该委托不包含任何参数,就可以使用下面的代码:
MessageArrived();
订阅事件的类是Display,它包含一个方法DisplayMessage()
    public class Display
    {
        public void DisplayMessage(string message)
        {
            Console.WriteLine("Message arrived:{0}",message);
        }
    }
这个方法匹配于委托类型方法的签名(返回类型和参数),所以可以使用它响应 MessageArrived 事件。
 
在进行如下定义后
            Connection myConnection = new Connection();
            Display myDisplay = new Display();
            myConnection.MessageArrived += new MessageHandler(myDisplay.DisplayMessage);
我们就可以看出,为 myConnection 对象的MessageArrived事件进行初始化时,因为MessageArrived事件是用MessageHandler代理类型定义的(void返回值和string参数),而Display类下的DisplayMessage方法的定义与这个委托类型方法的签名一致,所以可以将这个事件引发后要执行的方法转到这个方法上来。
下面是整个程序用到的源代码:
Connection
using System;
using System.Timers;
 
namespace Ch12Ex02
{
    public delegate void MessageHandler(string messageText);
 
    public class Connection
    {
        public event MessageHandler MessageArrived;
 
        private Timer pollTimer;
 
        public Connection()
        {
            pollTimer = new Timer(100);
            pollTimer.Elapsed += new ElapsedEventHandler(CheckForMessage);
        }
 
        public void Connect()
        {
            pollTimer.Start();
        }
 
        public void Disconnect()
        {
            pollTimer.Stop();
        }
 
        private void CheckForMessage(object source, ElapsedEventArgs e)
        {
            Console.WriteLine("checking for new message.");
            Random random = new Random();
            if((random.Next(9) == 0) && (MessageArrived != null))
            {
                MessageArrived("Hello Mum!");
            }
        }
    }
}
Display
using System;
 
namespace Ch12Ex02
{
    /// <summary>
    /// Display 的摘要说明。
    /// </summary>
    public class Display
    {
        public void DisplayMessage(string message)
        {
            Console.WriteLine("Message arrived:{0}",message);
        }
    }
}
Class1
using System;
 
namespace Ch12Ex02
{
    /// <summary>
    /// Class1 的摘要说明。
    /// </summary>
    class Class1
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main (string[] args)
        {
            Connection myConnection = new Connection();
            Display myDisplay = new Display();
            myConnection.MessageArrived += new MessageHandler(myDisplay.DisplayMessage);
            myConnection.Connect();
            Console.ReadLine();
        }
    }
}

本文出自 “努力学习的小熊” 博客,转载请与作者联系!

你可能感兴趣的:(基础,职场,学习,笔记,休闲)