rspec/rules/S3168/csharp/rule.adoc
Marco Borgeaud cd424756a0
Validate asciidoc ifdef/endif (#3311)
Fix kotlin:S6511
2023-10-18 09:43:40 +00:00

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[]