-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathCh11-1-MailManager.cs
212 lines (170 loc) · 7.44 KB
/
Ch11-1-MailManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
//#define CompilerImplementedEventMethods
using System;
using System.Threading;
public static class Events {
public static void Main() {
MailManager.Go();
TypeWithLotsOfEventsTest();
}
private static void TypeWithLotsOfEventsTest() {
// The code here tests the event
TypeWithLotsOfEvents twle = new TypeWithLotsOfEvents();
// Add a callback here
twle.Foo += HandleFooEvent;
twle.SimulateFoo();
Console.WriteLine("The callback was invoked 1 time above" + Environment.NewLine);
// Add another callback here
twle.Foo += HandleFooEvent;
twle.SimulateFoo();
Console.WriteLine("The callback was invoked 2 times above" + Environment.NewLine);
// Remove a callback here
twle.Foo -= HandleFooEvent;
twle.SimulateFoo();
Console.WriteLine("The callback was invoked 1 time above" + Environment.NewLine);
// Remove another callback here
twle.Foo -= HandleFooEvent;
twle.SimulateFoo();
Console.WriteLine("The callback was invoked 0 times above" + Environment.NewLine);
Console.WriteLine("Press <Enter> to terminate this application.");
Console.ReadLine();
}
private static void HandleFooEvent(object sender, FooEventArgs e) {
Console.WriteLine("Handling Foo Event here...");
}
}
///////////////////////////////////////////////////////////////////////////////
// Step #1: Define a type that will hold any additional information that
// should be sent to receivers of the event notification
internal sealed class NewMailEventArgs : EventArgs {
private readonly String m_from, m_to, m_subject;
public NewMailEventArgs(String from, String to, String subject) {
m_from = from; m_to = to; m_subject = subject;
}
public String From { get { return m_from; } }
public String To { get { return m_to; } }
public String Subject { get { return m_subject; } }
}
internal class MailManager {
public static void Go() {
// Construct a MailManager object
MailManager mm = new MailManager();
// Construct a Fax object passing it the MailManager object
Fax fax = new Fax(mm);
// Construct a Pager object passing it the MailManager object
Pager pager = new Pager(mm);
// Simulate an incoming mail message
mm.SimulateNewMail("Jeffrey", "Kristin", "I Love You!");
// Force the Fax object to unregister itself with the MailManager
fax.Unregister(mm);
// Simulate an incoming mail message
mm.SimulateNewMail("Jeffrey", "Mom & Dad", "Happy Birthday.");
}
#if CompilerImplementedEventMethods
// Step #2: Define the event member
public event EventHandler<NewMailEventArgs> NewMail;
#else
// Add private field which refers to the head of the delegate linked-list
private EventHandler<NewMailEventArgs> m_NewMail;
// Add an event member to the class
public event EventHandler<NewMailEventArgs> NewMail {
// Explicitly implement the 'add' method
add {
// Without thread-safety, add a handler
// (passed as 'value') to the delegate linked list
m_NewMail += value;
}
// Explicitly implement the 'remove' method
remove {
// Without thread-safety, remove a handler
// (passed as 'value') from the delegate linked list
m_NewMail -= value;
}
}
#endif
// Step #3: Define a method responsible for raising the event
// to notify registered objects that the event has occurred
// If this class is sealed, make this method private and nonvirtual
protected virtual void OnNewMail(NewMailEventArgs e) {
// Copy a reference to the delegate field now into a temporary field for thread safety
//e.Raise(this, ref m_NewMail);
#if CompilerImplementedEventMethods
EventHandler<NewMailEventArgs> temp = Volatile.Read(ref NewMail);
#else
EventHandler<NewMailEventArgs> temp = Volatile.Read(ref m_NewMail);
#endif
// If any methods registered interest with our event, notify them
if (temp != null) temp(this, e);
}
// Step #4: Define a method that translates the
// input into the desired event
public void SimulateNewMail(String from, String to, String subject) {
// Construct an object to hold the information we wish
// to pass to the receivers of our notification
NewMailEventArgs e = new NewMailEventArgs(from, to, subject);
// 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
OnNewMail(e);
}
}
public static class EventArgExtensions {
public static void Raise<TEventArgs>(this TEventArgs e, Object sender, ref EventHandler<TEventArgs> eventDelegate) {
// Copy a reference to the delegate field now into a temporary field for thread safety
EventHandler<TEventArgs> temp = Volatile.Read(ref eventDelegate);
// If any methods registered interest with our event, notify them
if (temp != null) temp(sender, e);
}
}
internal sealed class Fax {
// Pass the MailManager object to the constructor
public Fax(MailManager mm) {
// Construct an instance of the EventHandler<NewMailEventArgs>
// delegate that refers to our FaxMsg callback method.
// Register our callback with MailManager's NewMail event
mm.NewMail += FaxMsg;
}
// This is the method the MailManager will call
// when a new e-mail message arrives
private void FaxMsg(Object sender, NewMailEventArgs e) {
// 'sender' identifies the MailManager object in case
// we want to communicate back to it.
// 'e' identifies the additional event information
// the MailManager wants to give us.
// Normally, the code here would fax the e-mail message.
// This test implementation displays the info in the console
Console.WriteLine("Faxing mail message:");
Console.WriteLine(" From={0}, To={1}, Subject={2}",
e.From, e.To, e.Subject);
}
// This method could be executed to have the Fax object unregister itself with the NewMail
// event so that it no longer receives notifications
public void Unregister(MailManager mm) {
// Unregister ourself with MailManager's NewMail event
mm.NewMail -= FaxMsg;
}
}
///////////////////////////////////////////////////////////////////////////////
internal sealed 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.NewMail += SendMsgToPager;
}
// This is the method that the MailManager will call
// when a new e-mail message arrives
private void SendMsgToPager(Object sender, NewMailEventArgs 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(" From={0}, To={1}, Subject={2}", e.From, e.To, e.Subject);
}
public void Unregister(MailManager mm) {
// Unregister ourself with MailManager's ProcessMailMsg event
mm.NewMail -= SendMsgToPager;
}
}
//////////////////////////////// End of File //////////////////////////////////