Peter, his boss, and the universe were finally satisfied. Peter's boss and the universe were allowed to be notified of the events that interested them, reducing the burden of implementation and the cost of unnecessary round-trips. Peter could notify each of them, ignoring how long it took them to return from their target methods while still getting his results asynchronously. The result was the following complete solution: Delegate Sub WorkStarted() Delegate Sub WorkProgressing() Delegate Function WorkCompleted() As Integer Class Worker Public Event started As WorkStarted Public Event progressing As WorkProgressing Public completed As WorkCompleted Public Sub DoWork() Console.WriteLine("Worker: work started") RaiseEvent started() Console.WriteLine("Worker: work progressing") RaiseEvent progressing() Console.WriteLine("Worker: work completed") If Not (completed Is Nothing) Then Dim wc As WorkCompleted For Each wc In completed.GetInvocationList() Dim res As IAsyncResult = wc.BeginInvoke( _ New AsyncCallback(AddressOf WorkGraded), wc) Next End If End Sub Public Sub WorkGraded(ByVal res As IAsyncResult) Dim wc As WorkCompleted = CType(res.AsyncState, WorkCompleted) Dim grade As Integer = wc.EndInvoke(res) Console.WriteLine("Worker grade= " & grade.ToString()) End Sub End Class Class Boss Public Function WorkCompleted() As Integer System.Threading.Thread.Sleep(3000) Console.WriteLine("Better...") Return 4 ' out of 10 End Function End Class Class Universe Shared Sub WorkerStartedWork() Console.WriteLine("Universe notices worker starting work") End Sub Shared Function WorkerCompletedWork() As Integer System.Threading.Thread.Sleep(4000) Console.WriteLine("Universe pleased with worker's work") Return 7 End Function Shared Sub Main() Dim peter As Worker = New Worker() Dim theboss As Boss = New Boss() Dim d1, d2 As WorkCompleted d1 = AddressOf theboss.WorkCompleted d2 = AddressOf Universe.WorkerCompletedWork peter.completed = CType(System.Delegate.Combine(d1, d2), _ WorkCompleted) AddHandler peter.started, AddressOf Universe.WorkerStartedWork peter.DoWork() Console.WriteLine("Main: worker completed work") Console.ReadLine() End Sub End Class Peter knew that getting results asynchronously came with issues, because as soon as he fired events asynchronously, the target methods were likely to be executed on another thread, as was Peter's notification of when the target method has completed. However, Peter was familiar with Chapter 14: Multithreaded User Interfaces, so he understood how to manage such issues when building WinForms applications. And they all lived happily ever after. The end. |