Например, после вашего вопроса дискового ввода / вывода я недавно написал класс асинхронного сканера файлов (или в сотый раз за все годы). Его можно использовать повторно, как вы хотите, просто создав новый экземпляр и подключившись к событиям.
Я инкапсулировал функциональность внутри класса, который реализует межпотоковую безопасность. класс запускает события, чтобы уведомить абонента об обновлениях и о завершении.
Вы говорите, что «исходный код должен все еще считываться последовательно в отношении порядка выполнения кода», но понимаете, что потоки работают параллельно друг другу. Вот почему хорошо разделять структуры кода.
Это демонстрирует выделение многократно используемого кода в отдельный класс ...
Public Class FileScanner
Public Event Scan_Complete(sender As Object)
Public Event Scan_Update(sender As Object, filename As String)
Public Event Scan_Error(sender As Object, ex As Exception)
Private Delegate Sub del_ScanComplete()
Sub New(syncObject As Control, path String)
Me.SynchronizeObject = syncObject
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ScanFilesAsync), path)
End Sub
Private Sub ScanFilesAsync(ByVal state As Object)
' scan files here
' call the method to raise the Complete event
ScanComplete()
End Sub
Private Sub ScanComplete()
If SynchronizeObject.InvokeRequired Then
' we cant raise event on a different thread than our caller
' so lets invoke our method on the same caller thread
Dim d As New del_ScanComplete(AddressOf ScanComplete)
SynchronizeObject.Invoke(d)
Else
' no synchronize needed, tell the caller we are done
RaiseEvent Complete(Me)
End If
End Sub
End Class