Just getting into asynchronous programming and my end goal is to get the sha1 hashes of given set of files asynchronously and then continue processing said files with the computed hash value . I found the following MSDN blog post speaks on how to process the task results as the tasks finish: Link
The entire article is written in C# and my project is in VB.NET. I have attempted to rewrite the C# code to VB myself, however I must be missing a critical step or I am not fully understanding the process/syntax of Async
/Await
programming.
I am receiving the following error on the following lines:
Error 1 'Await' can only be used when contained within a method or lambda expression marked with the 'Async' modifier.
Dim t As Task(Of Integer) = Await bucket
Dim result As Integer= Await t
Dim t As Task(Of String) = Await bucket
Dim result As String = Await t
I can make the error go away by adding Async
to the containing Sub declaration. However, if I do that I receive another error because the containing method is main()
and it's a console Application.
Error 1 The 'Main' method cannot be marked 'Async'.
So I guess my question is, how can I use Await
an asynchronous task without making the containing method Async? My code below is just a tester for implementation in a WinForms project and I'd rather stay away from non native .NET pieces.
Below is the full code that I have converted from C# along with my little bit of code that does the computing of the sha1 hashes for the files:
Option Strict On
Option Explicit On
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Module Module1
Async Sub main()
' From the MSDN article
Dim taskArr As Task(Of Integer)() = {Task(Of Integer).Delay(3000).ContinueWith(Function(x) 3I), _
Task(Of Integer).Delay(1000).ContinueWith(Function(x) 1I), _
Task(Of Integer).Delay(2000).ContinueWith(Function(x) 2I), _
Task(Of Integer).Delay(5000).ContinueWith(Function(x) 5I), _
Task(Of Integer).Delay(4000).ContinueWith(Function(x) 4I)}
For Each bucket As Task(Of Task(Of Integer)) In Interleaved(taskArr)
Dim t As Task(Of Integer) = Await bucket ' Error Here
Dim result As Integer = Await t ' Error Here
Console.WriteLine("{0}: {1}", DateTime.Now, result)
Next
'My bit of code for computing the file hashes
Dim tasks As New List(Of Task(Of String))
Array.ForEach(New DirectoryInfo("C:\StackOverflow").GetFiles("*", SearchOption.AllDirectories), Sub(x) tasks.Add(getHashAsync(x)))
For Each bucket As Task(Of Task(Of String)) In Interleaved(tasks)
Dim t As Task(Of String) = Await bucket ' Error Here
Dim result As String = Await t ' Error Here
Console.WriteLine(result)
Next
End Sub
' Original C# code that I converted to VB myself
Public Function Interleaved(Of T)(tasks As IEnumerable(Of Task(Of T))) As Task(Of Task(Of T))()
Dim inputTasks As List(Of Task(Of T)) = tasks.ToList()
Dim buckets() As TaskCompletionSource(Of Task(Of T)) = New TaskCompletionSource(Of Task(Of T))(inputTasks.Count - 1I) {}
Dim results() As Task(Of Task(Of T)) = New Task(Of Task(Of T))(buckets.Length - 1I) {}
For i As Integer = 0I To buckets.Count - 1I Step 1I
buckets(i) = New TaskCompletionSource(Of Task(Of T))()
results(i) = buckets(i).Task
Next
Dim continuation As New Action(Of Task(Of T))(Function(completed As Task(Of T))
Dim bucket As TaskCompletionSource(Of Task(Of T)) = buckets(Interlocked.Increment(-1I))
Return bucket.TrySetResult(completed)
End Function)
For Each inputTask As Task(Of T) In inputTasks
inputTask.ContinueWith(continuation, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)
Next
Return results
End Function
' Get the sha1 hash of the file
Private Async Function getHashAsync(fle As FileInfo) As Task(Of String)
Using strm As New IO.FileStream(fle.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)
Return Await New Task(Of String)(Function() As String
Dim sb As New Text.StringBuilder()
Using sha1 As New System.Security.Cryptography.SHA1CryptoServiceProvider()
Array.ForEach(sha1.ComputeHash(strm), Sub(x As Byte) sb.Append(x.ToString("x2")))
End Using
Return sb.Append(" | ").Append(fle.FullName).ToString
End Function)
End Using
End Function
End Module