Using Delegates and Events 2 (来自一本49美元/817页2002年的书《C#.net web developer's guide》)
类别: ASP.NET教程
Figure 2.8 Continued
Continued.78 Chapter 2 • Introducing C# Programming
// appears in the message queue. Notice the signature matches
// that requried by AddEventCallback
public void logAddRequest( string FirstName, string LastName,
string MiddleName, string SSN )
{
string name = FirstName + " " + MiddleName + " " + LastName;
FileStream stream = new FileStream( m_fileName,
FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter writer = new StreamWriter( stream );
writer.BaseStream.Seek( 0, SeekOrigin.End );
writer.Write("{0} {1} /n", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
writer.Write( "Adding employee - Name: {0}, SSN: {1}",
name, SSN );
writer.Write("/n------------------------------------/n/n");
writer.Flush();
writer.Close();
}
}
A new class, EmployeeQueueLogger, has been added. It has a method
logAddRequest, which logs requests to add employees to a log file. The important
thing to note is that the logAddRequest method has a signature that matches the
AddEventCallback delegate signature. An instance of the logger is created in the
constructor of EmployeeQueueMonitor. The code that wires up the delegates is also
in the constructor and is shown here:
m_logger = new EmployeeQueueLogger( "log.txt" );
m_addEventCallback = new AddEventCallback( this.addEmployee );
m_addEventCallback += new AddEventCallback(
m_logger.logAddRequest );
http://www.syngress.com
Figure 2.8 Continued.Introducing C# Programming • Chapter 2 79
First, a new logger instance is created. Next, the delegate is initialized with a
first callback function to the addEmployee method of EmployeeQueueMonitor.
Finally, a second callback is added to the delegate, which will invoke the
logAddRequest of the EmployeeQueueLogger class. Notice that the plus sign is used
to add the second callback to the delegate. The plus sign (addition operator) has
been overloaded in the System.Delegate class of the .NET Framework to call the
Combine method of that class.The Combine method adds the callback to the list of
methods the delegate maintains.The minus sign (subtraction operator) is also
overloaded to call the Remove method, which removes a callback from the list of
methods the delegate maintains.The rest of the source code remains unchanged.
When the delegate is invoked in the start method of EmployeeQueueMonitor, both
EmployeeQueueMonitor.addEmployee and EmployeeQueueLogger.logAddRequest are
executed.
Events
The event model is often referred to as the publish/subscribe model or the listener
pattern. The idea behind the event model is that a class publishes the events that it
can raise. Consumers of the class object subscribe to the events they are interested
in.When the event occurs, the object that monitors the event notifies all sub-scribers
that the event has been raised.The subscribers then take some action.
The event model is often used in GUI programs. Handlers are set up for
common events, such as pressing a button.When the button press event occurs,
all subscribers registered for the button press event are invoked.The .NET
Framework uses the event model and in particular the System.Event delegate for
Windows Forms?Cbased applications.
The .NET Framework supplies a built in delegate of type System.Event. The
idea of events in the .NET Framework is to supply a single signature for the del-egate
regardless of the data that is passed to the subscribed callback. One of the
arguments for the Event delegate is an object derived from the .NET Framework
class System.EventArgs, which contains the data the callback needs.You declare a
class derived from System.EventArgs with the data your callback needs.When the
event takes place, you instantiate your derived EventArgs object and invoke the
event. Callback functions subscribed to the event are called passing the object
derived from EventArgs. Changes to the multicast delegate code sample that
implement events are shown in Figure 2.9.The full source code for this sample is
on the CD in the file Events.cs.
http://www.syngress.com.80 Chapter 2 • Introducing C# Programming
Figure 2.9 Relevant Portions of the Events.cs Program Listing
/// <summary>
/// Defines the data that will be passed from the event delegate to
/// the callback method when the event is raised
/// </summary>
class AddEmployeEventArgs : EventArgs
{
string m_FirstName;
string m_LastName;
string m_MiddleName;
string m_SSN;
public AddEmployeEventArgs( string FirstName,
string LastName, string MiddleName, string SSN )
{
m_FirstName = FirstName;
m_LastName = LastName;
m_MiddleName = MiddleName;
m_SSN = SSN;
}
// Event argument properties contain the data to pass to the
// callback methods subscribed to the event.
public string FirstName { get { return m_FirstName; } }
public string LastName { get { return m_LastName; } }
public string MiddleName {get { return m_MiddleName; } }
public string SSN { get { return m_SSN; } }
}
/// <summary>
/// Simulates monitoring a message queue. When a message appears
/// the event is raised and methods subscribed to the event
// are invoked.
/// </summary>
http://www.syngress.com
Continued.Introducing C# Programming • Chapter 2 81
class EmployeeQueueMonitor
{
// Event signature for AddEmployeeEvent
public delegate void AddEmployeeEvent( object sender,
AddEmployeEventArgs e );
// Instance of the AddEmployeeEvent
public event AddEmployeeEvent OnAddEmployee;
private EmployeeQueueLogger m_logger;
private Employees m_employees;
private int m_lengthQueue;
private string[, ] m_msgQueue =
{
{"Timothy", "Arthur", "Tucker", "555-55-5555"},
{"Sally", "Bess", "Jones", "666-66-6666" },
{"Jeff", "Michael", "Simms", "777-77-7777"},
{"Janice", "Anne", "Best", "888-88-8888" }
};
public EmployeeQueueMonitor( Employees employees )
{
m_employees = employees;
m_lengthQueue = 4;
m_logger = new EmployeeQueueLogger( "log.txt" );
// Register the methods that the Event will invoke when an add
// employee message is read from the message queue
OnAddEmployee +=
new AddEmployeeEvent( this.addEmployee );
http://www.syngress.com
Figure 2.9 Continued
Continued.82 Chapter 2 • Introducing C# Programming
OnAddEmployee +=
new AddEmployeeEvent( m_logger.logAddRequest );
}
// Drain the queue.
public void start()
{
if ( m_employees == null )
return;
for ( int i = 0; i < m_lengthQueue; i++ )
{
// Pop an add employee request off the queue
string FirstName = m_msgQueue[i,0];
string MiddleName = m_msgQueue[i,1];
string LastName = m_msgQueue[i,2];
string SSN = m_msgQueue[i,3];
Console.WriteLine( "Invoking delegate" );
// Create the event arguments to pass to the methods
// subscribed to the event and then invoke event resulting
// in the callbacks methods being executed, namely
// Employees.this.addEmployee() and
// EmployeeQueueLogger.logAddRequest()
AddEmployeEventArgs args = new AddEmployeEventArgs( FirstName,
LastName, MiddleName, SSN );
OnAddEmployee( this, args );
}
}
public void stop()
{
http://www.syngress.com
Figure 2.9 Continued
Continued.Introducing C# Programming • Chapter 2 83
// In a real communications program you would shut down
// gracefully.
}
// Called by event whenever a new add employee message appears
// in the message queue. Notice the signature matches that required
// by System.Event
public void addEmployee( object sender, AddEmployeEventArgs e )
{
Console.WriteLine( "In delegate, adding employee/r/n" );
int index = m_employees.Length;
m_employees[index] = new Employee ( e.FirstName, e.MiddleName,
e.LastName, e.SSN );
}
}
/// <summary>
/// Writes add employee events to a log file.
/// </summary>
class EmployeeQueueLogger
{
string m_fileName;
public EmployeeQueueLogger( string fileName )
{
m_fileName = fileName;
}
// Called by event whenever a new add employee message appears
// in the message queue. Notice the signature matches that required
// by System.Event
public void logAddRequest( object sender, AddEmployeEventArgs e )
http://www.syngress.com
Figure 2.9 Continued
Continued.84 Chapter 2 • Introducing C# Programming
{
string name = e.FirstName + " " + e.MiddleName + " " +
e.LastName;
FileStream stream = new FileStream( m_fileName,
FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter writer = new StreamWriter( stream );
writer.BaseStream.Seek( 0, SeekOrigin.End );
writer.Write("{0} {1} /n", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
writer.Write( "Adding employee - Name: {0}, SSN: {1}",
name, e.SSN );
writer.Write("/n------------------------------------/n/n");
writer.Flush();
writer.Close();
}
}
A new class, AddEmployeEventArgs, has been added. It contains the informa-tion
that will be passed to callback methods subscribed to the event. Notice the
data members of the AddEmployeEventArgs class are the same as the signature for
the AddEventCallback delegate in our previous sample. Instead of invoking the
callback with individual arguments, when using events, you pass a class object,
which contains the arguments instead.
Just as with the delegates samples, we declare the signature and create a
member variable for the delegate in EmployeeQueueMonitor class. The only differ-ence
is that the signature matches the signature necessary for events.The first
parameter is the object that raised the event, and the second is the object instance
that contains the arguments passed to subscribed callback methods.This is shown
here:
public delegate void AddEmployeeEvent( object sender,
http://www.syngress.com
Figure 2.9 Continued.Introducing C# Programming • Chapter 2 85
AddEmployeEventArgs e );
public event AddEmployeeEvent OnAddEmployee;
In the constructor of the class, we subscribe the callback methods to the
event as shown here:
OnAddEmployee +=
new AddEmployeeEvent( this.addEmployee );
OnAddEmployee +=
new AddEmployeeEvent( m_logger.logAddRequest );
The callback methods have the correct signature for event callbacks. Here are
the callback method’s signatures:
public void addEmployee( object sender, AddEmployeEventArgs e )
public void logAddRequest( object sender, AddEmployeEventArgs e )
When an add employee message is popped off the queue in the start method
of EmployeeQueueMonitor, an instance of the AddEmployeeEventArgs is created and
the event is invoked. Here is the code that accomplishes this:
AddEmployeEventArgs args = new AddEmployeEventArgs( FirstName,
LastName, MiddleName, SSN );
OnAddEmployee( this, args );
As you can see, using events instead of delegates is really just a syntactic dif-ference.
The code is nearly identical.The main benefit is that you don’t have a
different delegate signature for every delegate you create based on the data that is
passed to subscribed callbacks. Instead, the standard event delegate signature will
suffice.
Continued.78 Chapter 2 • Introducing C# Programming
// appears in the message queue. Notice the signature matches
// that requried by AddEventCallback
public void logAddRequest( string FirstName, string LastName,
string MiddleName, string SSN )
{
string name = FirstName + " " + MiddleName + " " + LastName;
FileStream stream = new FileStream( m_fileName,
FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter writer = new StreamWriter( stream );
writer.BaseStream.Seek( 0, SeekOrigin.End );
writer.Write("{0} {1} /n", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
writer.Write( "Adding employee - Name: {0}, SSN: {1}",
name, SSN );
writer.Write("/n------------------------------------/n/n");
writer.Flush();
writer.Close();
}
}
A new class, EmployeeQueueLogger, has been added. It has a method
logAddRequest, which logs requests to add employees to a log file. The important
thing to note is that the logAddRequest method has a signature that matches the
AddEventCallback delegate signature. An instance of the logger is created in the
constructor of EmployeeQueueMonitor. The code that wires up the delegates is also
in the constructor and is shown here:
m_logger = new EmployeeQueueLogger( "log.txt" );
m_addEventCallback = new AddEventCallback( this.addEmployee );
m_addEventCallback += new AddEventCallback(
m_logger.logAddRequest );
http://www.syngress.com
Figure 2.8 Continued.Introducing C# Programming • Chapter 2 79
First, a new logger instance is created. Next, the delegate is initialized with a
first callback function to the addEmployee method of EmployeeQueueMonitor.
Finally, a second callback is added to the delegate, which will invoke the
logAddRequest of the EmployeeQueueLogger class. Notice that the plus sign is used
to add the second callback to the delegate. The plus sign (addition operator) has
been overloaded in the System.Delegate class of the .NET Framework to call the
Combine method of that class.The Combine method adds the callback to the list of
methods the delegate maintains.The minus sign (subtraction operator) is also
overloaded to call the Remove method, which removes a callback from the list of
methods the delegate maintains.The rest of the source code remains unchanged.
When the delegate is invoked in the start method of EmployeeQueueMonitor, both
EmployeeQueueMonitor.addEmployee and EmployeeQueueLogger.logAddRequest are
executed.
Events
The event model is often referred to as the publish/subscribe model or the listener
pattern. The idea behind the event model is that a class publishes the events that it
can raise. Consumers of the class object subscribe to the events they are interested
in.When the event occurs, the object that monitors the event notifies all sub-scribers
that the event has been raised.The subscribers then take some action.
The event model is often used in GUI programs. Handlers are set up for
common events, such as pressing a button.When the button press event occurs,
all subscribers registered for the button press event are invoked.The .NET
Framework uses the event model and in particular the System.Event delegate for
Windows Forms?Cbased applications.
The .NET Framework supplies a built in delegate of type System.Event. The
idea of events in the .NET Framework is to supply a single signature for the del-egate
regardless of the data that is passed to the subscribed callback. One of the
arguments for the Event delegate is an object derived from the .NET Framework
class System.EventArgs, which contains the data the callback needs.You declare a
class derived from System.EventArgs with the data your callback needs.When the
event takes place, you instantiate your derived EventArgs object and invoke the
event. Callback functions subscribed to the event are called passing the object
derived from EventArgs. Changes to the multicast delegate code sample that
implement events are shown in Figure 2.9.The full source code for this sample is
on the CD in the file Events.cs.
http://www.syngress.com.80 Chapter 2 • Introducing C# Programming
Figure 2.9 Relevant Portions of the Events.cs Program Listing
/// <summary>
/// Defines the data that will be passed from the event delegate to
/// the callback method when the event is raised
/// </summary>
class AddEmployeEventArgs : EventArgs
{
string m_FirstName;
string m_LastName;
string m_MiddleName;
string m_SSN;
public AddEmployeEventArgs( string FirstName,
string LastName, string MiddleName, string SSN )
{
m_FirstName = FirstName;
m_LastName = LastName;
m_MiddleName = MiddleName;
m_SSN = SSN;
}
// Event argument properties contain the data to pass to the
// callback methods subscribed to the event.
public string FirstName { get { return m_FirstName; } }
public string LastName { get { return m_LastName; } }
public string MiddleName {get { return m_MiddleName; } }
public string SSN { get { return m_SSN; } }
}
/// <summary>
/// Simulates monitoring a message queue. When a message appears
/// the event is raised and methods subscribed to the event
// are invoked.
/// </summary>
http://www.syngress.com
Continued.Introducing C# Programming • Chapter 2 81
class EmployeeQueueMonitor
{
// Event signature for AddEmployeeEvent
public delegate void AddEmployeeEvent( object sender,
AddEmployeEventArgs e );
// Instance of the AddEmployeeEvent
public event AddEmployeeEvent OnAddEmployee;
private EmployeeQueueLogger m_logger;
private Employees m_employees;
private int m_lengthQueue;
private string[, ] m_msgQueue =
{
{"Timothy", "Arthur", "Tucker", "555-55-5555"},
{"Sally", "Bess", "Jones", "666-66-6666" },
{"Jeff", "Michael", "Simms", "777-77-7777"},
{"Janice", "Anne", "Best", "888-88-8888" }
};
public EmployeeQueueMonitor( Employees employees )
{
m_employees = employees;
m_lengthQueue = 4;
m_logger = new EmployeeQueueLogger( "log.txt" );
// Register the methods that the Event will invoke when an add
// employee message is read from the message queue
OnAddEmployee +=
new AddEmployeeEvent( this.addEmployee );
http://www.syngress.com
Figure 2.9 Continued
Continued.82 Chapter 2 • Introducing C# Programming
OnAddEmployee +=
new AddEmployeeEvent( m_logger.logAddRequest );
}
// Drain the queue.
public void start()
{
if ( m_employees == null )
return;
for ( int i = 0; i < m_lengthQueue; i++ )
{
// Pop an add employee request off the queue
string FirstName = m_msgQueue[i,0];
string MiddleName = m_msgQueue[i,1];
string LastName = m_msgQueue[i,2];
string SSN = m_msgQueue[i,3];
Console.WriteLine( "Invoking delegate" );
// Create the event arguments to pass to the methods
// subscribed to the event and then invoke event resulting
// in the callbacks methods being executed, namely
// Employees.this.addEmployee() and
// EmployeeQueueLogger.logAddRequest()
AddEmployeEventArgs args = new AddEmployeEventArgs( FirstName,
LastName, MiddleName, SSN );
OnAddEmployee( this, args );
}
}
public void stop()
{
http://www.syngress.com
Figure 2.9 Continued
Continued.Introducing C# Programming • Chapter 2 83
// In a real communications program you would shut down
// gracefully.
}
// Called by event whenever a new add employee message appears
// in the message queue. Notice the signature matches that required
// by System.Event
public void addEmployee( object sender, AddEmployeEventArgs e )
{
Console.WriteLine( "In delegate, adding employee/r/n" );
int index = m_employees.Length;
m_employees[index] = new Employee ( e.FirstName, e.MiddleName,
e.LastName, e.SSN );
}
}
/// <summary>
/// Writes add employee events to a log file.
/// </summary>
class EmployeeQueueLogger
{
string m_fileName;
public EmployeeQueueLogger( string fileName )
{
m_fileName = fileName;
}
// Called by event whenever a new add employee message appears
// in the message queue. Notice the signature matches that required
// by System.Event
public void logAddRequest( object sender, AddEmployeEventArgs e )
http://www.syngress.com
Figure 2.9 Continued
Continued.84 Chapter 2 • Introducing C# Programming
{
string name = e.FirstName + " " + e.MiddleName + " " +
e.LastName;
FileStream stream = new FileStream( m_fileName,
FileMode.OpenOrCreate, FileAccess.ReadWrite);
StreamWriter writer = new StreamWriter( stream );
writer.BaseStream.Seek( 0, SeekOrigin.End );
writer.Write("{0} {1} /n", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
writer.Write( "Adding employee - Name: {0}, SSN: {1}",
name, e.SSN );
writer.Write("/n------------------------------------/n/n");
writer.Flush();
writer.Close();
}
}
A new class, AddEmployeEventArgs, has been added. It contains the informa-tion
that will be passed to callback methods subscribed to the event. Notice the
data members of the AddEmployeEventArgs class are the same as the signature for
the AddEventCallback delegate in our previous sample. Instead of invoking the
callback with individual arguments, when using events, you pass a class object,
which contains the arguments instead.
Just as with the delegates samples, we declare the signature and create a
member variable for the delegate in EmployeeQueueMonitor class. The only differ-ence
is that the signature matches the signature necessary for events.The first
parameter is the object that raised the event, and the second is the object instance
that contains the arguments passed to subscribed callback methods.This is shown
here:
public delegate void AddEmployeeEvent( object sender,
http://www.syngress.com
Figure 2.9 Continued.Introducing C# Programming • Chapter 2 85
AddEmployeEventArgs e );
public event AddEmployeeEvent OnAddEmployee;
In the constructor of the class, we subscribe the callback methods to the
event as shown here:
OnAddEmployee +=
new AddEmployeeEvent( this.addEmployee );
OnAddEmployee +=
new AddEmployeeEvent( m_logger.logAddRequest );
The callback methods have the correct signature for event callbacks. Here are
the callback method’s signatures:
public void addEmployee( object sender, AddEmployeEventArgs e )
public void logAddRequest( object sender, AddEmployeEventArgs e )
When an add employee message is popped off the queue in the start method
of EmployeeQueueMonitor, an instance of the AddEmployeeEventArgs is created and
the event is invoked. Here is the code that accomplishes this:
AddEmployeEventArgs args = new AddEmployeEventArgs( FirstName,
LastName, MiddleName, SSN );
OnAddEmployee( this, args );
As you can see, using events instead of delegates is really just a syntactic dif-ference.
The code is nearly identical.The main benefit is that you don’t have a
different delegate signature for every delegate you create based on the data that is
passed to subscribed callbacks. Instead, the standard event delegate signature will
suffice.
- 上一篇: 【转载】关于垃圾回收机制
- 下一篇: .Net开放源码工程之二---正则表达式函数库
-= 资 源 教 程 =-
文 章 搜 索