您的位置:首页 > 编程语言 > C#

关于C#事件和委托的一点体会

2014-02-24 15:02 513 查看
 下面这段代码为:

/******************************************************************************

Module:  MailManager.cs

Notices: Copyright (c) 2002 Jeffrey Richter

******************************************************************************/

using System;

///////////////////////////////////////////////////////////////////////////////

class MailManager

{

    public class
ProcessMailMsgEventArgs : EventArgs

    {

       
// 1. Type defining information passed to receivers of the
event

       
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

   
//    that
receivers must implement

    public
delegate void ProcessMailMsgEventHandler(

      
Object sender, ProcessMailMsgEventArgs args);

    // 3. The
event itself

    public event
ProcessMailMsgEventHandler ProcessMailMsg;

    // 4.
Protected, virtual method responsible for notifying
registered

   
//    objects of
the event

    protected
virtual 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

   
//    This
method is called when a new e-mail message arrives

    public void
SimulateArrivingMsg(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 the
event

       
// occurred. If no type overrides this method, our object
will

       
// notify all the objects that registered interest in the
event

       
OnProcessMailMsg(e);

    }

}

///////////////////////////////////////////////////////////////////////////////

class Fax

{

    // Pass the
MailManager object to the constructor

    public
Fax()

    {

    }

    // This
is the method that the MailManager will call

    // when a
new e-mail message arrives

    public
virtual 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);

    }

    public
void 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 void
Unregister(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

{

    public
override  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 the
MailManager object to the constructor

    public
Pager(MailManager mm)

    {

       
// Construct an instance of the ProcessMailMsgEventHandler

       
// delegate that refers to our SendMsgToPager callback
method.

       
// Register our callback with MailManager's ProcessMailMsg
event

       
mm.ProcessMailMsg +=

          
new MailManager.ProcessMailMsgEventHandler(SendMsgToPager);

    }

    // This
is the method that the MailManager will call

    // when a
new 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 a
pager.

       
// 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 void
Main()

    {

       
// 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 the
MailManager

       
fax.Unregister(mm);

       
// Simulate an incoming mail messa
4000
ge

       
mm.SimulateArrivingMsg("Jeffrey Richter", "Mom & Dad",

          
"My birthday",

          
"Thanks for the great presents last year");

    }

}

执行结果如下:

Faxing mail
message:
   To:
Jeffrey Richter

   From: Santa

   Subject: Christmas

   Body: Thanks for the great
presents last year

Faxing1 mail
message:

   To: Jeffrey Richter

   From: Santa

   Subject: Christmas

   Body: Thanks for the great
presents last year

Sending mail message to pager:

   To: Jeffrey Richter

   From: Santa

   Subject: Christmas

   Body: Thanks for the great
presents last year

Faxing1 mail message:

   To: Jeffrey Richter

   From: Mom & Dad

   Subject: My birthday

   Body: Thanks for the great
presents last year

Sending mail message to pager:

   To: Jeffrey Richter

   From: Mom & Dad

   Subject: My birthday

   Body: Thanks for the great
presents last year

 

注意上面红颜色部分,出现这样输出结果的原因是名为FaxMsg的委托方法是虚方法,而将委托方法改为虚函数,则不会有任何影响。

在C/C++中,非静态成员函数是不同作为回调函数的,因为非静态成员函数成员函数与具体的对象有关系,所以我最初很不能理解为什么FaxMsg可以用作回调函数,最近似乎有所领悟,那就是在把委托实例加入事件的委托链时,除了将方法的地址传入外,同时也将this指针传入了,这部分工作应该是编译器完成的。如果是虚方法,则动态绑定方法的地址。如果是静态方法,则忽略this指针。

这样,上面的代码就好理解了,我估计应该是这样的,不知道对不对,也许《Applied
Microsoft.NET Framework
Programming》中会讲到,不过我还没有看到那么远。到时候再验证吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: