forked from cuicheng11165/clr-via-csharp-4th-edition-code
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCh17-1-Delegates.cs
335 lines (278 loc) · 10.9 KB
/
Ch17-1-Delegates.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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Reflection;
public sealed class Program {
public static void Main() {
DelegateIntro.Go();
GetInvocationList.Go();
AnonymousMethods.Go();
DelegateReflection.Go("TwoInt32s", "Add", "123", "321");
DelegateReflection.Go("TwoInt32s", "Subtract", "123", "321");
DelegateReflection.Go("OneString", "NumChars", "Hello there");
DelegateReflection.Go("OneString", "Reverse", "Hello there");
}
}
internal sealed class DelegateIntro {
// Declare a delegate type; instances refer to a method that
// takes an Int32 parameter and returns void.
internal delegate void Feedback(Int32 value);
public static void Go() {
StaticDelegateDemo();
InstanceDelegateDemo();
ChainDelegateDemo1(new DelegateIntro());
ChainDelegateDemo2(new DelegateIntro());
}
private static void StaticDelegateDemo() {
Console.WriteLine("----- Static Delegate Demo -----");
Counter(1, 3, null);
Counter(1, 3, new Feedback(DelegateIntro.FeedbackToConsole));
Counter(1, 3, new Feedback(FeedbackToMsgBox)); // "Program." is optional
Console.WriteLine();
}
private static void InstanceDelegateDemo() {
Console.WriteLine("----- Instance Delegate Demo -----");
DelegateIntro di = new DelegateIntro();
Counter(1, 3, new Feedback(di.FeedbackToFile));
Console.WriteLine();
}
private static void ChainDelegateDemo1(DelegateIntro di) {
Console.WriteLine("----- Chain Delegate Demo 1 -----");
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fb3 = new Feedback(di.FeedbackToFile);
Feedback fbChain = null;
fbChain = (Feedback)Delegate.Combine(fbChain, fb1);
fbChain = (Feedback)Delegate.Combine(fbChain, fb2);
fbChain = (Feedback)Delegate.Combine(fbChain, fb3);
Counter(1, 2, fbChain);
Console.WriteLine();
fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox));
Counter(1, 2, fbChain);
}
private static void ChainDelegateDemo2(DelegateIntro di) {
Console.WriteLine("----- Chain Delegate Demo 2 -----");
Feedback fb1 = new Feedback(FeedbackToConsole);
Feedback fb2 = new Feedback(FeedbackToMsgBox);
Feedback fb3 = new Feedback(di.FeedbackToFile);
Feedback fbChain = null;
fbChain += fb1;
fbChain += fb2;
fbChain += fb3;
Counter(1, 2, fbChain);
Console.WriteLine();
fbChain -= new Feedback(FeedbackToMsgBox);
Counter(1, 2, fbChain);
}
private static void Counter(Int32 from, Int32 to, Feedback fb) {
for (Int32 val = from; val <= to; val++) {
// If any callbacks are specified, call them
if (fb != null)
fb(val);
}
}
private static void FeedbackToConsole(Int32 value) {
Console.WriteLine("Item=" + value);
}
private static void FeedbackToMsgBox(Int32 value) {
MessageBox.Show("Item=" + value);
}
private void FeedbackToFile(Int32 value) {
StreamWriter sw = new StreamWriter("Status", true);
sw.WriteLine("Item=" + value);
sw.Close();
}
}
internal static class GetInvocationList {
// Define a Light component.
internal sealed class Light {
// This method returns the light's status.
public String SwitchPosition() {
return "The light is off";
}
}
// Define a Fan component.
internal sealed class Fan {
// This method returns the fan's status.
public String Speed() {
throw new InvalidOperationException("The fan broke due to overheating");
}
}
// Define a Speaker component.
internal sealed class Speaker {
// This method returns the speaker's status.
public String Volume() {
return "The volume is loud";
}
}
// Definition of delegate that allows querying a component's status.
private delegate String GetStatus();
public static void Go() {
// Declare an empty delegate chain.
GetStatus getStatus = null;
// Construct the three components, and add their status methods
// to the delegate chain.
getStatus += new GetStatus(new Light().SwitchPosition);
getStatus += new GetStatus(new Fan().Speed);
getStatus += new GetStatus(new Speaker().Volume);
// Show consolidated status report reflecting
// the condition of the three components.
Console.WriteLine(GetComponentStatusReport(getStatus));
}
// Method that queries several components and returns a status report
private static String GetComponentStatusReport(GetStatus status) {
// If the chain is empty, there’s is nothing to do.
if (status == null) return null;
// Use this to build the status report.
StringBuilder report = new StringBuilder();
// Get an array where each element is a delegate from the chain.
Delegate[] arrayOfDelegates = status.GetInvocationList();
// Iterate over each delegate in the array.
foreach (GetStatus getStatus in arrayOfDelegates) {
try {
// Get a component's status string, and append it to the report.
report.AppendFormat("{0}{1}{1}", getStatus(), Environment.NewLine);
}
catch (InvalidOperationException e) {
// Generate an error entry in the report for this component.
Object component = getStatus.Target;
report.AppendFormat(
"Failed to get status from {1}{2}{0} Error: {3}{0}{0}",
Environment.NewLine,
((component == null) ? "" : component.GetType() + "."),
getStatus.GetMethodInfo().Name, e.Message);
}
}
// Return the consolidated report to the caller.
return report.ToString();
}
}
internal static class AnonymousMethods {
public static void Go() {
// Create and initialize a String array
String[] names = { "Jeff", "Kristin", "Aidan" };
// Get just the names that have a lowercase 'i' in them.
Char charToFind = 'i';
names = Array.FindAll(names, delegate(String name) { return (name.IndexOf(charToFind) >= 0); });
// Convert each string's characters to uppercase
names = Array.ConvertAll<String, String>(names, delegate(String name) { return name.ToUpper(); });
// Sort the names
Array.Sort(names, delegate(String name1, String name2) { return String.Compare(name1, name2); });
// Display the results
Array.ForEach(names, delegate(String name) { Console.WriteLine(name); });
}
private sealed class AClass {
private static void CallbackWithoutNewingADelegateObject() {
ThreadPool.QueueUserWorkItem(delegate(Object obj) { Console.WriteLine(obj); }, 5);
}
}
private sealed class AClass2 {
private static void UsingLocalVariablesInTheCallbackCode(Int32 numToDo) {
// Some local variables
Int32[] squares = new Int32[numToDo];
AutoResetEvent done = new AutoResetEvent(false);
// Do a bunch of tasks on other threads
for (Int32 n = 0; n < squares.Length; n++) {
ThreadPool.QueueUserWorkItem(
delegate(Object obj) {
Int32 num = (Int32)obj;
// This task would normally more time consuming
squares[num] = num * num;
// If last task, let main thread continue running
if (Interlocked.Decrement(ref numToDo) == 0)
done.Set();
}, n);
}
// Wait for all the other threads to finish
done.WaitOne();
// Show the results
for (Int32 n = 0; n < squares.Length; n++)
Console.WriteLine("Index {0}, Square={1}", n, squares[n]);
}
}
}
// Here are some different delegate definitions
internal delegate Object TwoInt32s(Int32 n1, Int32 n2);
internal delegate Object OneString(String s1);
internal static class DelegateReflection {
public static void Go(params String[] args) {
if (args.Length < 2) {
String usage =
@"Usage:" +
"{0} delType methodName [Arg1] [Arg2]" +
"{0} where delType must be TwoInt32s or OneString" +
"{0} if delType is TwoInt32s, methodName must be Add or Subtract" +
"{0} if delType is OneString, methodName must be NumChars or Reverse" +
"{0}" +
"{0}Examples:" +
"{0} TwoInt32s Add 123 321" +
"{0} TwoInt32s Subtract 123 321" +
"{0} OneString NumChars \"Hello there\"" +
"{0} OneString Reverse \"Hello there\"";
Console.WriteLine(usage, Environment.NewLine);
return;
}
// Convert the delType argument to a delegate type
Type delType = Type.GetType(args[0]);
if (delType == null) {
Console.WriteLine("Invalid delType argument: " + args[0]);
return;
}
Delegate d;
try {
// Convert the Arg1 argument to a method
MethodInfo mi = typeof(DelegateReflection).GetTypeInfo().GetDeclaredMethod(args[1]);
// Create a delegate object that wraps the static method
d = mi.CreateDelegate(delType);
}
catch (ArgumentException) {
Console.WriteLine("Invalid methodName argument: " + args[1]);
return;
}
// Create an array that that will contain just the arguments
// to pass to the method via the delegate object
Object[] callbackArgs = new Object[args.Length - 2];
if (d.GetType() == typeof(TwoInt32s)) {
try {
// Convert the String arguments to Int32 arguments
for (Int32 a = 2; a < args.Length; a++)
callbackArgs[a - 2] = Int32.Parse(args[a]);
}
catch (FormatException) {
Console.WriteLine("Parameters must be integers.");
return;
}
}
if (d.GetType() == typeof(OneString)) {
// Just copy the String argument
Array.Copy(args, 2, callbackArgs, 0, callbackArgs.Length);
}
try {
// Invoke the delegate and show the result
Object result = d.DynamicInvoke(callbackArgs);
Console.WriteLine("Result = " + result);
}
catch (TargetParameterCountException) {
Console.WriteLine("Incorrect number of parameters specified.");
}
}
// This callback method takes 2 Int32 arguments
private static Object Add(Int32 n1, Int32 n2) {
return n1 + n2;
}
// This callback method takes 2 Int32 arguments
private static Object Subtract(Int32 n1, Int32 n2) {
return n1 - n2;
}
// This callback method takes 1 String argument
private static Object NumChars(String s1) {
return s1.Length;
}
// This callback method takes 1 String argument
private static Object Reverse(String s1) {
return new String(s1.Reverse().ToArray());
}
}