138 lines
4.1 KiB
Plaintext
138 lines
4.1 KiB
Plaintext
== Why is this an issue?
|
|
|
|
An https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async[`async`] method with a `void` return type does not follow the https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/task-asynchronous-programming-model[task asynchronous programming (TAP)] model since the return type should be https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task[`Task`] or https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1[`Task<TResult>`]
|
|
|
|
Doing so prevents control over the https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/async-scenarios[asynchronous execution], such as:
|
|
|
|
* waiting for the execution to complete
|
|
* catching any exception that might occur during execution
|
|
* testing execution behavior
|
|
|
|
=== Exceptions
|
|
|
|
* Methods with the https://learn.microsoft.com/en-us/dotnet/api/system.eventhandler[`EventHandler`] delegate signature.
|
|
+
|
|
Using `void` for `EventHandler` is compliant with the TAP model.
|
|
+
|
|
[source,csharp]
|
|
----
|
|
public async void button1_Click(object sender, EventArgs e)
|
|
{
|
|
await DoSomethingAsync();
|
|
}
|
|
----
|
|
* Methods name matching `On[A-Z]\w*` pattern.
|
|
+
|
|
Some frameworks may not use the same `EventHandler` method signature
|
|
+
|
|
[source,csharp]
|
|
----
|
|
public async void OnClick(EventContext data)
|
|
{
|
|
await DoSomethingAsync();
|
|
}
|
|
----
|
|
|
|
== How to fix it
|
|
|
|
Update the return type of the method from `void` to `Task`.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,csharp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
private async void ThrowExceptionAsync() // Noncompliant: async method return type is 'void'
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
public void Method()
|
|
{
|
|
try
|
|
{
|
|
ThrowExceptionAsync();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// The exception is never caught here
|
|
throw;
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
==== Compliant solution
|
|
|
|
[source,csharp,diff-id=1,diff-type=compliant]
|
|
----
|
|
private async Task ThrowExceptionAsync() // Compliant: async method return type is 'Task'
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
public void Method()
|
|
{
|
|
try
|
|
{
|
|
await ThrowExceptionAsync();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// The exception is caught here
|
|
throw;
|
|
}
|
|
}
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async[`async` (C# Reference)]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/async-scenarios[Asynchronous programming]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/task-asynchronous-programming-model[Task asynchronous programming model]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task[`Task` Class]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1[`Task<TResult>` Class]
|
|
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/api/system.eventhandler[`EventHandler` Delegate]
|
|
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Return "Task" instead.
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== on 30 Jun 2015, 13:36:13 Ann Campbell wrote:
|
|
\[~tamas.vajk] I don't understand the code snippets. The `async Task` method doesn't return anything.
|
|
|
|
|
|
Also, could you morph the Noncompliant Example into a Compliant Solution, please?
|
|
|
|
=== on 1 Jul 2015, 07:10:48 Tamas Vajk wrote:
|
|
\[~ann.campbell.2] I added the compliant solution.
|
|
|
|
|
|
A method with `async` keyword returning a `Task` is like a non `async` method with `void` return type. Similarly in an `async Task<int>` method we can return a simple `int`. (\https://msdn.microsoft.com/en-us/library/hh524395.aspx)
|
|
|
|
=== on 1 Jul 2015, 11:31:53 Ann Campbell wrote:
|
|
\[~tamas.vajk] that makes me wonder if we should generalize this rule to catch _any_ `async` method that does not return a `Task`...?
|
|
|
|
=== on 1 Jul 2015, 11:49:54 Tamas Vajk wrote:
|
|
\[~ann.campbell.2] That's a compiler error (CS1983, _The return type of async must be void, Task or Task<T>_).
|
|
|
|
=== on 1 Jul 2015, 11:59:39 Ann Campbell wrote:
|
|
Okay, thanks [~tamas.vajk]
|
|
|
|
endif::env-github,rspecator-view[]
|