Async Return Types (C# and Visual Basic)
Async methods have three possible return types: Task<TResult>, Task, and void. In Visual Basic, the void return type is written as a Sub procedure. For more information about async methods, see Asynchronous Programming with Async and Await (C# and Visual Basic).
Each return type is examined in one of the following sections, and you can find a full example that uses all three types at the end of the topic.
This topic contains the following sections.
The Task<TResult> return type is used for an async method that contains a Return (Visual Basic) or return (C#) statement in which the operand has type TResult.
In the following example, the TaskOfT_MethodAsync async method contains a return statement that returns an integer. Therefore, the method declaration must specify a return type of Task(Of Integer) in Visual Basic or Task<int> in C#.
When TaskOfT_MethodAsync is called from within an await expression, the await expression retrieves the integer value (the value of leisureHours) that's stored in the task that's returned by TaskOfT_MethodAsync. For more information about await expressions, see Await Operator (Visual Basic) or await (C# Reference).
The following code calls and awaits method TaskOfT_MethodAsync. The result is assigned to the result1 variable.
You can better understand how this happens by separating the call to TaskOfT_MethodAsync from the application of Await or await, as the following code shows. A call to method TaskOfT_MethodAsync that isn't immediately awaited returns a Task(Of Integer) or Task<int>, as you would expect from the declaration of the method. The task is assigned to the integerTask variable in the example. Because integerTask is a Task<TResult>, it contains a Result property of type TResult. In this case, TResult represents an integer type. When Await or await is applied to integerTask, the await expression evaluates to the contents of the Result property of integerTask. The value is assigned to the result2 variable.
Caution
|
|---|
|
The Result property is a blocking property. If you try to access it before its task is finished, the thread that's currently active is blocked until the task completes and the value is available. In most cases, you should access the value by using Await or await instead of accessing the property directly. |
The display statements in the following code verify that the values of the result1 variable, the result2 variable, and the Result property are the same. Remember that the Result property is a blocking property and shouldn't be accessed before its task has been awaited.
Async methods that don't contain a return statement or that contain a return statement that doesn't return an operand usually have a return type of Task. Such methods would be void-returning methods (Sub procedures in Visual Basic) if they were written to run synchronously. If you use a Task return type for an async method, a calling method can use an await operator to suspend the caller's completion until the called async method has finished.
In the following example, async method Task_MethodAsync doesn't contain a return statement. Therefore, you specify a return type of Task for the method, which enables Task_MethodAsync to be awaited. The definition of the Task type doesn't include a Result property to store a return value.
Task_MethodAsync is called and awaited by using an await statement instead of an await expression, similar to the calling statement for a synchronous Sub or void-returning method. The application of an await operator in this case doesn't produce a value.
The following code calls and awaits method Task_MethodAsync.
As in the previous Task<TResult> example, you can separate the call to Task_MethodAsync from the application of an await operator, as the following code shows. However, remember that a Task doesn't have a Result property, and that no value is produced when an await operator is applied to a Task.
The following code separates calling Task_MethodAsync from awaiting the task that Task_MethodAsync returns.
The primary use of the void return type (Sub procedures in Visual Basic) is in event handlers, where a void return type is required. A void return also can be used to override void-returning methods or for methods that perform activities that can be categorized as "fire and forget." However, you should return a Task wherever possible, because a void-returning async method can't be awaited. Any caller of such a method must be able to continue to completion without waiting for the called async method to finish, and the caller must be independent of any values or exceptions that the async method generates.
The caller of a void-returning async method can't catch exceptions that are thrown from the method, and such unhandled exceptions are likely to cause your application to fail. If an exception occurs in an async method that returns a Task or Task<TResult>, the exception is stored in the returned task, and rethrown when the task is awaited. Therefore, make sure that any async method that can produce an exception has a return type of Task or Task<TResult> and that calls to the method are awaited.
For more information about how to catch exceptions in async methods, see try-catch (C# Reference) or Try...Catch...Finally Statement (Visual Basic).
The following code defines an async event handler.
The following Windows Presentation Foundation (WPF) project contains the code examples from this topic.
To run the project, perform the following steps:
-
Start Visual Studio.
-
On the menu bar, choose File, New, Project.
The New Project dialog box opens.
-
In the Installed, Templates category, choose Visual Basic or Visual C#, and then choose Windows. Choose WPF Application from the list of project types.
-
Enter AsyncReturnTypes as the name of the project, and then choose the OK button.
The new project appears in Solution Explorer.
-
In the Visual Studio Code Editor, choose the MainWindow.xaml tab.
If the tab is not visible, open the shortcut menu for MainWindow.xaml in Solution Explorer, and then choose Open.
-
In the XAML window of MainWindow.xaml, replace the code with the following code.
A simple window that contains a text box and a button appears in the Design window of MainWindow.xaml.
-
In Solution Explorer, open the shortcut menu for MainWindow.xaml.vb or MainWindow.xaml.cs, and then choose View Code.
-
Replace the code in MainWindow.xaml.vb or MainWindow.xaml.cs with the following code.
-
Choose the F5 key to run the program, and then choose the Start button.
The following output should appear.
Application can continue working while the Task<T> runs. . . . Value of result1 variable: 5 Value of result2 variable: 5 Value of integerTask.Result: 5 Sorry for the delay. . . . Application can continue working while the Task runs. . . . Sorry for the delay. . . . All done, exiting button-click event handler.
Caution