写这篇博文的目的是要记录一下学习委托与事件的心的与代码,方便之后查阅
1、委托,是一个函数的签名,规定了函数的返回值与参数列表。类似于这类函数的一个代理,签名相同但是用途不同的函数s,要执行的时候就通过代理来执行,使得函数执行得到诸多的方便。delegate相当于一个类,具有类的一些特性。
2、事件,事件就是应用程序中各个模块交互的一种信号。
一个事件的示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Timers; namespace DelegateLearn { public delegate void GreetPeopel(string name); class Program { static int count = 0; static string display = "用时间事件来说明------------!!!!"; static void Main(string[] args) { Timer myTimer = new Timer(100); myTimer.Elapsed += new ElapsedEventHandler(WriteChar); myTimer.Start(); Console.ReadKey(); } static void WriteChar(object source, ElapsedEventArgs e) { Console.Write(display[count++ % display.Length]); } } }
Timer对象有一个Elapsed事件,这个事件要求的时间处理程序签名是System.Timers.ElapsedEventHandler委托类型,为.NET Framework定义的标准委托之一,要求的函数签名为:
void functionName(object source, ElapsedEventArgs e);
然后将处理程序与事件关联起来,给事件添加一个事件处理程序,并启动计时器,然后会每个100ms产生一个Elapsed事件。
myTimer.Elapsed += new ElapsedEventHandler(WriteChar);
自定义事件
时间有几个重要的组成部分,1、用于事件的委托,规定了事件处理方法的签名,2、时间的定义,public event [指定的委托类型] [事件名称],3、事件的产生,在产生事件的类里面通过一定方法产生该事件,4、在用到该事件的地方,订阅该事件,将事件处理程序与事件联系起来。
一个自定义事件的例子
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Timers; namespace DelegateLearn { public delegate void MessageHandler(string messageText); class Connect { Timer myTimer = new Timer(500); public event MessageHandler MessageArrived; public Connect() { myTimer.Elapsed +=new ElapsedEventHandler(CheckMessage); myTimer.Start(); } static Random random = new Random(); private void CheckMessage(object source, ElapsedEventArgs e) { Console.WriteLine("Waiting for message....."); if (random.Next(9) == 0 && MessageArrived != null) { MessageArrived("Hello event"); } } } class Display { public void DisplayMessage(string message) { Console.WriteLine("Message: " + message); } } class Program { static void DisplayMessage(string message) { Console.WriteLine("Message: " + message); } static void Main(string[] args) { //Display displayMessage = new Display(); Connect connect = new Connect(); connect.MessageArrived +=new MessageHandler(DisplayMessage); Console.ReadKey(); } } }
代码中的事件为MessageArrived,用于事件的委托为
public delegate void MessageHandler(string messageText);
那么事件处理方法的签名就被规定为上述的形式,在程序中通过将类的事件处理程序与类的事件联系起来就可以处理事件了。
connect.MessageArrived += new MessageHandler(DisplayMessage);
完善上面的例子
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Timers; namespace DelegateLearn { public delegate void MessageHandler(Connection source, MessageArrivedEventArgs e); public class MessageArrivedEventArgs : EventArgs { private string message; public string Message { get { return message; } } public MessageArrivedEventArgs() { message = "No message sent."; } public MessageArrivedEventArgs(string newMessage) { message = newMessage; } } public class Connection { private string name; public string Name { get { return name; } set { name = value; } } Timer myTimer = new Timer(500); public event MessageHandler MessageArrived; public Connection() { myTimer.Elapsed +=new ElapsedEventHandler(CheckMessage); } public void Connect() { myTimer.Start(); } public void DisConnect() { myTimer.Stop(); } static Random random = new Random(); private void CheckMessage(object source, ElapsedEventArgs e) { Console.WriteLine("Waiting for message....."); if (random.Next(9) == 0 && MessageArrived != null) { MessageArrived(this, new MessageArrivedEventArgs("Hello Event!!")); } } } class Display { public void DisplayMessage(object source, MessageArrivedEventArgs e) { Console.WriteLine("Message from: " + ((Connection)source).Name); Console.WriteLine("Message: " + e.Message); } } class Program { static void Main(string[] args) { Display displayMessage = new Display(); Connection connect = new Connection(); connect.Name = "远房亲戚"; connect.MessageArrived +=new MessageHandler(displayMessage.DisplayMessage); connect.Connect(); Console.ReadKey(); } } }
这段代码,基本上和标准的时间处理程序差不多。
定义事件委托的时候,加入了引发事件对象的引用,和一个事件参数。
发送一个引发事件对象的引用,将其作为事件处理程序的一个参数,就可以为不同的对象定制处理程序的响应。利用该引用可以访问源对象,包括他的属性。通过发送派生于System.EventArgs的事件参数类的引用,就可以将其他必要信息作为参数,方便处理。
这里有一点要注意,一个事件可能会调用很多的事件处理函数,这些函数都返回一个值,那么会使用哪个返回值呢?系统处理这个问题的方式是,只允许访问最后一个调用的时间处理方法返回的值。
匿名方法:
delegate(parameters) { //方法代码 }
其中parameters是一个参数列表,这些参数匹配要实例化的委托类型,由匿名方法的代码使用。
总结:
- 事件的声明[访问修饰符] event [delegate] [事件名]
- 事件处理程序的订阅 “+=”
- 事件委托类型的参数传递。