Anonymous Delegates


At this point, Peter was using delegates to notify interested parties in the process of his work and using delegates to get notified when grades were available on the work he had completed. The delegates provided by his boss and the universe were provided by separate entities, so it made sense that they were encapsulated in methods on those entities. However, in the case of the WorkGraded method, there was really no good reason for this to be a separate method except the syntactic requirements of C# 1.0. As of C# 2.0, Peter could drop the code required to handle the processing of his work grade into an anonymous delegate:

class Worker {   ...   public void DoWork() {     ...     Console.WriteLine("Worker: work completed");     if( this.Completed != null ) {       foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {         wc.BeginInvoke(delegate(IAsyncResult result) {           WorkCompleted wc2 = (WorkCompleted)result.AsyncState;           int grade = wc2.EndInvoke(result);           Console.WriteLine("Worker grade= {0}", grade);         },         wc);       }     }   } }


Here, instead of passing in the name of a method to call when his work had been graded, he was passing in the body of the method itself as designated with a different use of the delegate keyword to create a method with no name (and therefore "anonymous"). The body of the method was fundamentally the same in that Peter still passed the Work-Completed delegate as a parameter to BeginInvoke and then pulled it out of AsyncState for use in extracting the result. However, Peter knew that one of the benefits of anonymous delegates was that he could make use of the variables in the surrounding context from within the anonymous delegate body, and so he rewrote his code thusly:

class Worker {   ...   public void DoWork() {     ...     Console.WriteLine("Worker: work completed");     if( this.Completed != null ) {       foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {         wc.BeginInvoke(delegate(IAsyncResult result) {           // Use wc variable from surrounding context (ERR!)           int grade = wc.EndInvoke(result);           Console.WriteLine("Worker grade= {0}", grade);         },         null);       }     }   } }


This code compiled just fine, but when it was run, it caused the following exception to be thrown:

System.InvalidOperationException:   The IAsyncResult object provided does not match this delegate.


The problem was that although the wc variable was allowed to be used in the anonymous delegate, it was still being used by the for-each statement. As soon as the asynchronous invocation began, the wc variable changed, and the delegate used to start things (wc) no longer matched the async result passed as an argument to the anonymous delegate. Peter slapped his forehead and created a hybrid solution:

class Worker {   ...   public void DoWork() {     ...     Console.WriteLine("Worker: work completed");     if( this.Completed != null ) {       foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {         // Create an unchanging variable referencing the current delegate         WorkCompleted wc2 = wc;         wc.BeginInvoke(delegate(IAsyncResult result) {           // Use wc2 variable from surrounding context           int grade = wc2.EndInvoke(result);           Console.WriteLine("Worker grade= {0}", grade);         },         null);       }     }   } }





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