在处理事件中的Timer.Elapsed事件的委托包含了事件处理程序中常见的两类参数,如下所示:
object.source——引发事件的对象的引用
ElapsedEventArgs e——由事件传送的参数
在这个事件(以及其他的事件中)使用object类型参数的原因是,我们常常要为由不同对象引发的几个相同事件使用同一个事件处理程序,但仍要指定是哪个对象生成了事件。
要说明这一点,下面将扩展使用事件中的示例。
1)在之前的目录中新建一个控制台应用程序Ch13Ex03。
2)复制之前的Program.cs、Connection.cs和Display.cs的代码,并将每个文件中的Ch13Ex02名称控件改为Ch13Ex03。
3)添加一个新类MessageArrivedEventArgs,修改MessageArrivedEventArgs.cs,如下所示:
namespace Ch13Ex03
{
public class MessageArrivedEventArgs : EventArgs
{
private string message;
public string Message
{
get{ return meaasge;}
}
public MessageArrivedEventArgs(string newMessage) => message = newMessage;
}
}
4)修改Connection.cs,如下所示:
namespace Ch13Ex03
{
//delegate definition removed
public class Connection
{
public event EventHandler<MessageArrivedEventArgs> MessageArrived;
public string Name { get; set; }
...
public void CheckForMessage(object source, EventArgs e)
{
WriteLine("Checking for new message.");
if ((random.Next(9) == 0) && (MessageArrived != null))
{
MessageArrived(this, new MessageArrivedEventArgs("Hello Mami!"));
}
}
}
}
5)修改Display.cs,如下所示:
public void DisplayMessage(object source, MessageArrivedEventArgs e)
{
WriteLine($"Message arrived from: {((Connection)source).Name}");
WriteLine($"Message Text:{e.Message}");
}
6)修改Program.cs,如下所示:
static void Main(string[] args)
{
Connection myConnection1 = new Connection();
myConnection1.Name = "First connection.";
Connection myConnection2 = new Connection();
myConnection2.Name = "Second connection.";
Display myDisplay = new Display();
myConnection1.MessageArrived += myDisplay.DisplayMessage;
myConnection2.MessageArrived += myDisplay.DisplayMessage;
myConnection1.Connect();
myConnection2.Connect();
System.Threading.Thread.Sleep(200);
ReadKey();
}
发送一个引发事件的对象引用,将其作为事件处理程序的一个参数,就可以为不同对象定制处理程序的响应。利用该引用可以访问源对象,包括它的属性。
通过发送包含在派生于System.EventArgs(与ElapsedEventArgs相同)的类中的参数,就可以将其他的必要信息提供为参数(例如,MessageArrivedEventArgs类上的Message参数)。
另外,这些参数也将得益于多样性。可为MessageArrived事件定义一个处理程序,如下所示:
public void DisplayMessage(object source,EventArgs e)
{
WriteLine($"Message arrived from: {((Connection)source).Name}");
WriteLine($"Message Text:{((MessageArrivedEventArgs)e).Message}");
}
这个应用程序奖项以前那样执行,但DisplayMessage()方法变得更加通用(至少从理论上讲是这样的——需要使用更多实现代码,才能满足生产环境的要求)。这个处理程序还可以处理其他事件,例如Timer.Elapsed事件,但必须修改程序的内部代码,这样,在引发这个事件时,发送过来的参数才会得到正确处理(以这种方式把它们转换为Connection和MessageArrivedEventArgs对象,会抛出一个异常,所以这里应使用as运算符,并检查null值)。