The pattern below smells for a few reasons, but for the purposes of this question, let's focus on the global variables and the event handler:
Dim objectQueue As New BlockingCollection(Of Object)
Dim objectQueueCancel As New CancellationTokenSource
Sub Main()
Task.Run(Sub()
If Console.ReadKey.KeyChar() = "c" Then objectQueueCancel.Cancel()
End Sub)
Dim t1 As Task = Task.Run(Sub() NonBlockingConsumer())
Dim t2 As Task = Task.Run(Sub() NonBlockingProducer())
Task.WaitAll(t1, t2)
objectQueueCancel.Dispose()
Console.WriteLine("Press the Enter key to exit.")
Console.ReadLine()
End Sub
Private Sub NonBlockingProducer()
Dim sourceObjects As ICollection(Of Object) = Nothing 'Sanitized for StackOverflow
For Each sourceObject In sourceObjects
If sourceObject.IsEnabled Then
Dim objectEventGenerator As New objectEventGenerator(sourceObject)
AddHandler objectEventGenerator.objectEvent, AddressOf Handler_ObjectEvent
objectEventGenerator.Enabled = True
End If
If objectQueue.IsAddingCompleted Then Exit For
Next sourceObject
End Sub
Public Sub Handler_ObjectEvent(ByVal sender As Object, ByVal e As objectEventArgs)
If Not objectQueue.IsAddingCompleted Then
If Not e.EventException Is Nothing Then
Environment.ExitCode = -1
Else
Dim itemToAdd As Object = Nothing
Dim itemQueued As Boolean = False
Do
Try
itemQueued = objectQueue.TryAdd(itemToAdd, 0, objectQueueCancel.Token) 'TODO Tweak enqueue timeout
Catch ex As OperationCanceledException
objectQueue.CompleteAdding()
Exit Do
End Try
If itemQueued Then
itemToAdd = Nothing
Else
Thread.Sleep(0)
End If
Loop While Not itemQueued
End If
End If
End Sub
The only way of programmatically accessing the objects in the target use case is through an event listener, and while this code executes it has two pesky global variables. If I define / Dim the BlockingCollection and CancellationTokenSource in the Main() sub, I would have to pass them (I expect ByRef) into the event handler by way of NonBlockingProducer(). However, the event handler's signature is fixed, i.e. I can't simply extend it to be able to pass the variables in...
What is the "proper" way of refactoring this to eliminate the global variables?