Delegates


Once upon a time, in a strange land south of here, there was a worker named Peter. He was a diligent worker who would readily accept requests from his boss. However, his boss was a mean, untrusting man who insisted on steady progress reports. Because Peter did not want his boss standing in his office looking over his shoulder, Peter promised to notify his boss whenever his work progressed. Peter implemented this promise by periodically calling his boss back via a typed reference like so:

class Worker {   Boss boss;   public void Advise(Boss boss) {     this.boss = boss;   }   public void DoWork() {     Console.WriteLine("Worker: work started");     if( this.boss != null ) this.boss.WorkStarted();     Console.WriteLine("Worker: work progressing");     if( this.boss != null ) this.boss.WorkProgressing();     Console.WriteLine("Worker: work completed");     if( this.boss != null ) {       int grade = this.boss.WorkCompleted();       Console.WriteLine("Worker grade= {0}", grade);     }   } } class Boss {   public void WorkStarted() {     // Boss doesn't care   }   public void WorkProgressing() {     // Boss doesn't care   }   public int WorkCompleted() {     Console.WriteLine("It's about time!");     return 2; // out of 10   } } class Universe {   static void Main() {     Worker peter = new Worker();     Boss boss = new Boss();     peter.Advise(boss);     peter.DoWork();     Console.WriteLine("Main: worker completed work");     Console.ReadLine();   } }


Interfaces

Now Peter was a special person. Not only was he able to put up with his mean-spirited boss, but he also had a deep connection with the universe around him. So much so that he felt that the universe was interested in his progress. Unfortunately, there was no way for Peter to advise the universe of his progress unless he added a special Advise method and special callbacks just for the universe, in addition to keeping his boss informed. What Peter really wanted to do was to separate the list of potential notifications from the implementation of those notification methods. And so he decided to split the methods into an interface:

interface IWorkerEvents {    void WorkStarted();    void WorkProgressing();    int WorkCompleted(); } class Worker {   IWorkerEvents events;   public void Advise(IWorkerEvents events) {     this.events = events;   }   public void DoWork() {     Console.WriteLine("Worker: work started");     if( this.events != null ) this.events.WorkStarted();     Console.WriteLine("Worker: work progressing");     if( this.events != null ) this.events.WorkProgressing();     Console.WriteLine("Worker: work completed");     if( this.events!= null ) {       int grade = this.events.WorkCompleted();       Console.WriteLine("Worker grade= {0}", grade);     }   } } class Boss : IWorkerEvents {   public void WorkStarted() {     // Boss doesn't care   }   public void WorkProgressing() {     // Boss doesn't care   }   public int WorkCompleted() {     Console.WriteLine("It's about time!");     return 3; // out of 10   } }


Unfortunately, Peter was so busy talking his boss into implementing this interface that he didn't get around to notifying the universe, but he knew he would soon. At least, he'd abstract the reference of his boss far away from him so that others who implemented the IWorkerEvents interface could be notified of his work progress.

Still, his boss complained bitterly. "Peter!" his boss fumed. "Why are you bothering to notify me when you start your work or when your work is progressing?!? I don't care about those events. Not only do you force me to implement those methods, but you're wasting valuable work time waiting for me to return from the event, which is further expanded when I am far away! Can't you figure out a way to stop bothering me?"

And so, Peter decided that while interfaces were useful for many things, when it came to events, their granularity was not fine enough. He wished to be able to notify interested parties only of the events that matched their hearts' desires. So, he decided to break the methods out of the interface into separate delegate functions, each of which acted as a tiny interface of one method:

delegate void WorkStarted(); delegate void WorkProgressing(); delegate int WorkCompleted(); class Worker {   public WorkStarted Started;   public WorkProgressing Progressing;   public WorkCompleted Completed;   public void DoWork() {     Console.WriteLine("Worker: work started");     if( this.Started != null ) this.Started();     Console.WriteLine("Worker: work progressing");     if( this.Progressing != null ) this.Progressing();     Console.WriteLine("Worker: work completed");     if( this.Completed != null ) {       int grade = this.Completed();       Console.WriteLine("Worker grade= {0}", grade);     }   } } class Boss {   public int WorkCompleted() {     Console.WriteLine("It's about time!");     return 4; // out of 10   } } class Universe {   static void Main() {     Worker peter = new Worker();     Boss boss = new Boss();     // NOTE: We've replaced the Advise method with the assignment operation     peter.Completed = new WorkCompleted(boss.WorkCompleted);     peter.DoWork();     Console.WriteLine("Main: worker completed work");     Console.ReadLine();   } }


And, because Peter was under so much pressure, he decided to take advantage of the shorthand notation for assigning delegates provided by C# 2.0:

class Universe {   static void Main() {     ...     peter.Completed = boss.WorkCompleted;     ...   } }


Static Listeners

Delegates accomplished the goal of not bothering Peter's boss with events that he didn't want, but still Peter had not managed to get the universe on his list of listeners. Because the universe is an all-encompassing entity, it didn't seem right to hook delegates to instance members (imagine how many resources multiple instances of the universe would need . . .). Instead, Peter needed to hook delegates to static members, which delegates supported fully:

class Universe {   static void WorkerStartedWork() {     Console.WriteLine("Universe notices worker starting work");   }   static int WorkerCompletedWork() {     Console.WriteLine("Universe pleased with worker's work");     return 7;   }   static void Main() {     Worker peter = new Worker();     Boss boss = new Boss();     peter.Completed = boss.WorkCompleted;     peter.Started = Universe.WorkerStartedWork;        peter.Completed = Universe.WorkerCompletedWork; // Oops!     peter.DoWork();     Console.WriteLine("Main: worker completed work");     Console.ReadLine();   } }





Windows Forms 2.0 Programming
Windows Forms 2.0 Programming (Microsoft .NET Development Series)
ISBN: 0321267966
EAN: 2147483647
Year: 2006
Pages: 216

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