2023-05-03 11:06:20 +02:00
== Why is this an issue?
2024-06-24 15:00:14 +02:00
When https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-switch-statement[switch] statements have large sets of multi-line `case` clauses, the code becomes hard to read and maintain.
For example, the https://www.sonarsource.com/docs/CognitiveComplexity.pdf[Cognitive Complexity] is going to be particularly high.
In such scenarios, it's better to refactor the `switch` to only have single-line case clauses.
When all the `case` clauses of a `switch` statement are single-line, the readability of the code is not affected.
Moreover, `switch` statements with single-line `case` clauses can easily be converted into https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression[`switch` expressions], which are more concise for assignment and avoid the need for `break` statements.
2020-06-30 12:47:33 +02:00
2023-06-15 16:30:42 +02:00
=== Exceptions
2024-06-24 15:00:14 +02:00
This rule ignores:
* `switch` statements over `Enum` arguments
* fall-through cases
* `return`, `break` and `throw` statements in case clauses
2023-06-15 16:30:42 +02:00
== How to fix it
2024-06-24 15:00:14 +02:00
Extract the logic of multi-line `case` clauses into separate methods.
2020-06-30 12:47:33 +02:00
2023-06-15 16:30:42 +02:00
=== Code examples
2020-06-30 14:49:38 +02:00
2024-06-24 15:00:14 +02:00
The examples below use the "Maximum number of case" property set to `4`.
Note that from C# 8, you can use https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression[`switch` expression].
2023-06-15 16:30:42 +02:00
==== Noncompliant code example
[source,csharp,diff-id=1,diff-type=noncompliant]
2020-06-30 12:47:33 +02:00
----
2024-06-24 15:00:14 +02:00
public int MapChar(char ch, int value)
2020-06-30 12:47:33 +02:00
{
2024-06-24 15:00:14 +02:00
switch(ch) // Noncompliant
2020-06-30 12:47:33 +02:00
{
2024-06-24 15:00:14 +02:00
case 'a':
return 1;
case 'b':
return 2;
case 'c':
return 3;
// ...
case '-':
if (value > 10)
{
return 42;
}
else if (value < 5 && value > 1)
{
return 21;
}
return 99;
default:
return 1000;
2020-06-30 12:47:33 +02:00
}
}
----
2023-06-15 16:30:42 +02:00
==== Compliant solution
2020-06-30 12:47:33 +02:00
2023-06-15 16:30:42 +02:00
[source,csharp,diff-id=1,diff-type=compliant]
2020-06-30 12:47:33 +02:00
----
2024-06-24 15:00:14 +02:00
public int MapChar(char ch, int value)
{
switch(ch) // Compliant: All 5 cases are single line statements
{
case 'a':
return 1;
case 'b':
return 2;
case 'c':
return 3;
// ...
case '-':
return HandleDash(value);
default:
return 1000;
}
}
2020-06-30 12:47:33 +02:00
2024-06-24 15:00:14 +02:00
private int HandleDash(int value)
2020-06-30 12:47:33 +02:00
{
2024-06-24 15:00:14 +02:00
if (value > 10)
{
return 42;
}
else if (value < 5 && value > 1)
2020-06-30 12:47:33 +02:00
{
2024-06-24 15:00:14 +02:00
return 21;
}
return 99;
}
----
For this example, a `switch` expression is more concise and clear:
[source,csharp]
----
public int MapChar(char ch, int value) =>
ch switch // Compliant
{
'a' => 1,
'b' => 2,
'c' => 3,
// ...
'-' => HandleDash(value),
_ => 1000,
2020-06-30 12:47:33 +02:00
};
2024-06-24 15:00:14 +02:00
private int HandleDash(int value)
{
if (value > 10)
{
return 42;
}
else if (value < 5 && value > 1)
2020-06-30 12:47:33 +02:00
{
2024-06-24 15:00:14 +02:00
return 21;
2020-06-30 12:47:33 +02:00
}
2024-06-24 15:00:14 +02:00
return 99;
2020-06-30 12:47:33 +02:00
}
----
2023-06-15 16:30:42 +02:00
include::../resources-dotnet.adoc[]
2023-06-22 10:38:01 +02:00
2024-06-24 15:00:14 +02:00
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements#the-switch-statement[The `switch` statement]
* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression[C#: Switch Expression]
2021-09-20 15:38:42 +02:00
2023-06-15 16:30:42 +02:00
include::../rspecator-dotnet.adoc[]
2021-06-02 20:44:38 +02:00