/******************************************************************************
Module: MailManager.cs
Notices: Copyright (c) 2002 Jeffrey Richter
******************************************************************************/
using System;
///////////////////////////////////////////////////////////////////////////////
class MailManager
{
public classProcessMailMsgEventArgs : EventArgs
{
// 1. Type defining information passed to receivers of theevent
public ProcessMailMsgEventArgs(
String from, String to, String subject, String body)
{
this.from = from;
this.to = to;
this.subject = subject;
this.body = body;
}
public readonly String from, to, subject, body;
}
// 2.Delegate type defining the prototype of the callback method
// thatreceivers must implement
publicdelegate void ProcessMailMsgEventHandler(
Object sender, ProcessMailMsgEventArgs args);
// 3. Theevent itself
public eventProcessMailMsgEventHandler ProcessMailMsg;
// 4.Protected, virtual method responsible for notifyingregistered
// objects ofthe event
protectedvirtual void OnProcessMailMsg(ProcessMailMsgEventArgs e)
{
// Has any objects registered interest with our event?
if (ProcessMailMsg != null)
{
// Yes, notify all the objects
ProcessMailMsg(this, e); //激发事件,将消息传递给订阅此事件的所有对象
}
}
// 5.Method that translates the input into the desired event
// Thismethod is called when a new e-mail message arrives
public voidSimulateArrivingMsg(String from, String to,
String subject, String body)
{
// Construct an object to hold the information we wish
// to pass to the receivers of our notification
ProcessMailMsgEventArgs e =
new ProcessMailMsgEventArgs(from, to, subject, body);
// Call our virtual method notifying our object that theevent
// occurred. If no type overrides this method, our objectwill
// notify all the objects that registered interest in theevent
OnProcessMailMsg(e);
}
}
///////////////////////////////////////////////////////////////////////////////
class Fax
{
// Pass theMailManager object to the constructor
publicFax()
{
}
// Thisis the method that the MailManager will call
// when anew e-mail message arrives
publicvirtual void FaxMsg(
Object sender, MailManager.ProcessMailMsgEventArgs e)
{
// 'sender' identifies the MailManager in case
// we want to communicate back to it.
// 'e' identifies the additional event information
// that the MailManager wants to give us.
// Normally, the code here would fax the e-mail message.
// This test implementation displays the info on the console
Console.WriteLine("Faxing mail message:");
Console.WriteLine(
" To:{0}\n From:{1}\n Subject:{2}\n Body: {3}\n",
e.from, e.to, e.subject, e.body);
}
publicvoid Register(MailManager mm)
{
// Construct an instance of the ProcessMailMsgEventHandler
// delegate that refers to our FaxMsg callback method.
MailManager.ProcessMailMsgEventHandler callback =
new MailManager.ProcessMailMsgEventHandler(FaxMsg);
mm.ProcessMailMsg+= callback;
}
public voidUnregister(MailManager mm)
{
// Construct an instance of the ProcessMailMsgEventHandler
// delegate that refers to our FaxMsg callback method.
MailManager.ProcessMailMsgEventHandler callback =
new MailManager.ProcessMailMsgEventHandler(FaxMsg);
// Unregister ourself with MailManager's ProcessMailMsg event
mm.ProcessMailMsg -= callback;
}
}
class Fax1 : Fax
{
publicoverride void FaxMsg(
Object sender, MailManager.ProcessMailMsgEventArgs e)
{
// 'sender' identifies the MailManager in case
// we want to communicate back to it.
// 'e' identifies the additional event information
// that the MailManager wants to give us.
// Normally, the code here would fax the e-mail message.
// This test implementation displays the info on the console
Console.WriteLine("Faxing1 mail message:");
Console.WriteLine(
" To:{0}\n From:{1}\n Subject:{2}\n Body: {3}\n",
e.from, e.to, e.subject, e.body);
}
}
///////////////////////////////////////////////////////////////////////////////
class Pager
{
// Pass theMailManager object to the constructor
publicPager(MailManager mm)
{
// Construct an instance of the ProcessMailMsgEventHandler
// delegate that refers to our SendMsgToPager callbackmethod.
// Register our callback with MailManager's ProcessMailMsgevent
mm.ProcessMailMsg +=
new MailManager.ProcessMailMsgEventHandler(SendMsgToPager);
}
// Thisis the method that the MailManager will call
// when anew e-mail message arrives
private void SendMsgToPager(
Object sender, MailManager.ProcessMailMsgEventArgs e)
{
// 'sender' identifies the MailManager in case
// we want to communicate back to it.
// 'e' identifies the additional event information
// that the MailManager wants to give us.
// Normally, the code here would send the e-mail message to apager.
// This test implementation displays the info on the console
Console.WriteLine("Sending mail message to pager:");
Console.WriteLine(
" To:{0}\n From:{1}\n Subject:{2}\n Body: {3}\n",
e.from, e.to, e.subject, e.body);
}
}
///////////////////////////////////////////////////////////////////////////////
class App
{
static voidMain()
{
// Construct a MailManager object
MailManager mm = new MailManager();
// Construct a Fax object passing it the MailManager object
Fax fax = new Fax();
Fax fax1 = new Fax1();
fax.Register(mm);
fax1.Register(mm);
// Construct a Pager object passing it the MailManager object
Pager pager = new Pager(mm);
// Simulate an incoming mail message
mm.SimulateArrivingMsg("Jeffrey Richter",
"Santa",
"Christmas",
"Thanks for the great presents last year");
// Force the Fax object to unregister itself with theMailManager
fax.Unregister(mm);
// Simulate an incoming mail message
mm.SimulateArrivingMsg("Jeffrey Richter", "Mom & Dad",
"My birthday",
"Thanks for the great presents last year");
}
}
执行结果如下:
Faxing mailmessage:
To:Jeffrey Richter
From: Santa
Subject: Christmas
Body: Thanks for the greatpresents last year
Faxing1 mailmessage:
To: Jeffrey Richter
From: Santa
Subject: Christmas
Body: Thanks for the greatpresents last year
Sending mail message to pager:
To: Jeffrey Richter
From: Santa
Subject: Christmas
Body: Thanks for the greatpresents last year
Faxing1 mail message:
To: Jeffrey Richter
From: Mom & Dad
Subject: My birthday
Body: Thanks for the greatpresents last year
Sending mail message to pager:
To: Jeffrey Richter
From: Mom & Dad
Subject: My birthday
Body: Thanks for the greatpresents last year
注意上面红颜色部分,出现这样输出结果的原因是名为FaxMsg的委托方法是虚方法,而将委托方法改为虚函数,则不会有任何影响。
在C/C++中,非静态成员函数是不同作为回调函数的,因为非静态成员函数成员函数与具体的对象有关系,所以我最初很不能理解为什么FaxMsg可以用作回调函数,最近似乎有所领悟,那就是在把委托实例加入事件的委托链时,除了将方法的地址传入外,同时也将this指针传入了,这部分工作应该是编译器完成的。如果是虚方法,则动态绑定方法的地址。如果是静态方法,则忽略this指针。
这样,上面的代码就好理解了,我估计应该是这样的,不知道对不对,也许《AppliedMicrosoft.NET FrameworkProgramming》中会讲到,不过我还没有看到那么远。到时候再验证吧。