Events


Unfortunately, the universe, being very busy and unaccustomed to paying attention to individuals, had managed to replace Peter's boss's delegate with its own. This was an unintended side effect of making the delegate fields public in Peter's Worker class. Likewise, if Peter's boss got impatient, he could decide to fire Peter's delegates himself (which is just the kind of rude thing that Peter's boss was apt to do):

 // Peter's boss taking matters into his own hands if( peter.completed != null ) peter.completed(); 

Peter wanted to make sure that neither of these could happen. He realized that he needed to add registration and unregistration functions for each delegate so that subscribers could add or remove themselves but couldn't clear the entire list or fire his events. Instead of implementing these functions himself, Peter used the event keyword to make the C# compiler build these methods for him:

 class Worker { ...   public  event  WorkStarted started;   public  event  WorkProgressing progressing;   public  event  WorkCompleted completed; } 

Peter knew that the event keyword erected a property around a delegate, allowing only clients to add or remove themselves (using the += and -= operators, if the client was written in C#), forcing his boss and the universe to play nicely :

 static void Main() {   Worker peter = new Worker();   Boss boss = new Boss();   peter.completed += new WorkCompleted(boss.WorkCompleted);   peter.started += new WorkStarted(Universe.WorkerStartedWork);   peter.completed += new WorkCompleted(Universe.WorkerCompletedWork);   peter.DoWork();   Console.WriteLine("Main: worker completed work");   Console.ReadLine(); } 

Harvesting All Results

At this point, Peter breathed a sigh of relief. He had managed to satisfy the requirements of all his subscribers without having to be closely coupled with the specific implementations . However, he noticed that although both his boss and the universe provided grades of his work, Peter was receiving only one of the grades. In the face of multiple subscribers, he really wanted to harvest all of their results. So, he reached into his delegate and pulled out the list of subscribers so that he could call each of them manually:

 public void DoWork() {   ...   Console.WriteLine("Worker: work completed");   if( completed != null ) {  foreach( WorkCompleted wc in completed.GetInvocationList() ) {   int grade = wc();  Console.WriteLine("Worker grade= " + grade);  }  } } 

Asynchronous Notification: Fire and Forget

In the meantime, his boss and the universe had been distracted with other things, and this meant that the time it took them to grade Peter's work had been greatly expanded:

 class Boss {   public int WorkCompleted() {  System.Threading.Thread.Sleep(3000);  Console.WriteLine("Better..."); return 6; /* out of 10 */   } } class Universe {   static int WorkerCompletedWork() {  System.Threading.Thread.Sleep(4000);  Console.WriteLine("Universe is pleased with worker's work");     return 7;   }   ... } 

Unfortunately, because Peter was notifying each subscriber one at a time, waiting for each to grade him, these notifications now took up quite a bit of his time when he should have been working. So, he decided to forget the grade and just fire the event asynchronously:

 public void DoWork() {   ...   Console.WriteLine("Worker: work completed");   if( completed != null ) {  foreach( WorkCompleted wc in completed.GetInvocationList() ) {   wc.BeginInvoke(null, null);   }  } } 

Asynchronous Notification: Polling

This clever trick allowed Peter to notify the subscribers while letting him get back to work immediately, letting the process thread pool invoke the delegate. Over time, however, Peter found that he missed the feedback on his work. He knew that he did a good job and appreciated the praise of the universe as a whole (if not his boss specifically ). So, he fired the event asynchronously but polled periodically, looking for the grade to be available:

 public void DoWork() {   ...   Console.WriteLine("Worker: work completed");   if( completed != null ) {  foreach( WorkCompleted wc in completed.GetInvocationList() ) {   IAsyncResult res = wc.BeginInvoke(null, null);   while( !res.IsCompleted ) System.Threading.Thread.Sleep(1);   int grade = wc.EndInvoke(res);  Console.WriteLine("Worker grade= " + grade);  }  } } 

Asynchronous Notification: Delegates

Unfortunately, Peter was back to the very thing he wanted his boss to avoid with him in the beginning: looking over the shoulder of the entity doing the work. So, he decided to employ another delegate as a means of notification when the asynchronous work was completed, allowing him to get back to work immediately but still be notified when his work had been graded:

 public void DoWork() {   ...   Console.WriteLine("Worker: work completed");   if( completed != null ) {  foreach( WorkCompleted wc in completed.GetInvocationList() ) {   wc.BeginInvoke(new AsyncCallback(WorkGraded), wc);   }  } }  void WorkGraded(IAsyncResult res) {   WorkCompleted wc = (WorkCompleted)res.AsyncState;   int grade = wc.EndInvoke(res);  Console.WriteLine("Worker grade= " + grade);  }  


Windows Forms Programming in C#
Windows Forms Programming in C#
ISBN: 0321116208
EAN: 2147483647
Year: 2003
Pages: 136
Authors: Chris Sells

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net