Multiple cases on switch with C# 8

Asked

Viewed 142 times

6

On seeing this question about multiple conditions in the switch, reminded me of a problem I had and I couldn’t solve.

In C# 8, a new syntax for switch:

int num = ObterUmNumero();

var descricao = num switch
{
    0 => "Zero",
    1 => "Um",
    2 => "Dois",
    _ => "Indefinido"
};

Is a syntax sugar and the code is clear and clear, but it occurred to me as follows, how do I apply a value to multiple cases?

For example, how to make this more conventional syntax work?

var descricao = string.Empty;
switch(num)
{
    case -1:
    case 0:
        descricao = "Invalido";
        break;
}

3 answers

6

The first question on the subject we need to understand is about the syntax of the two constructions.

Although they both use the same keyword they are completely different. They took the name to not have to create another reserved word in the language, which would probably break several existing codes, but not have used one match made a lot of people misunderstand this difference.

The first switch is a syntactic sugar for if and for all intents and purposes he is the same as a if. The switch traditional is not a if, he’s a jump list, is an execution deviation optimization based on a possible value table, so it is very limited in what you can put there.

This is explained in How the switch works behind the scenes?. Language is different, but all who have this mechanism in the right way essentially work in the same way.

But C# was a little smarter and he did it even in the case of Pattern matching create a jump list optimized where you can do this. And even in a more organized way than was done with the switch traditional.

It is possible to see that the CIL has specific instruction to mount the switch and this will generate a code more suitable for the situation. See on Sharplab. Jitter will be responsible for assembling the most suitable real code to execute the need. Note that although the compiler does nothing on it itself, there is the possibility of Jitter doing more optimizations, so an instruction was created in CIL. So we can’t claim that the way more match of switch C# is clearly inefficient, it will depend on the specific scenario and the implementation of Jitter.

Already the switch is generated by the compiler creating the jump list "in hand". See on Sharplab..

See that the documentation clearly distinguishes the declaration switch of the expression of match. This syntax of match was introduced in C# 6, and has been improving with each version.

Leandro’s response shows how to do with the match (expression switch) to accept two values up to C# 8 (starting with 6 of course). For all intents and purposes it is a if, there is no specific optimization, neither by the compiler (of course he does the best he can) nor will it be done later by Jitter. See on Sharplab.

I just don’t really like the other example that he put together because it generates unnecessary memory allocations. But that’s collateral to the matter we’re dealing with here.

The LINQ response shows another way to solve it and is available in C# 9 onwards. It is much easier to read and write. It also generates a different final code that can be optimized by Jitter, so it’s much more interesting than just being more "cute". See on Sharplab. Note that it tends to create a jump list even in this case, in a possibly equal or better way than the switch traditional, just no guarantees for the language, will depend on the Jitter.

In fact, if we look at the final Jittado code in the implementation used, it generates a very efficient code. See on Sharplab. Seems more or less as efficient as the switch traditional (looking over). But if you need the maximum optimization need to keep up with the end result, you can’t trust the compiler ever.

  • "Although they both use the same keyword they are completely different. They took advantage of the name to not have to create another reserved word in the language" I thought the same thing when I saw this Feature :) Good analysis, especially by the Sharplab links

6


It is not possible to make two patterns fall in the same case. Note that the switch expression is different from statement (statement) switch.

The simplest way to achieve what you want is to create an expression that fits both cases.

In C# 9 this is much simpler because it is possible to use the disjunctive pattern or.

int num = ObterUmNumero();

var descricao = num switch
{
    -1 or 0 => "Invalido",
    1 => "Um",
    2 => "Dois",
    _ => "Indefinido"
};

The Pattern matching C# 9 also allows use relational patterns.

var descricao = num switch
{
    < 1 => "Inválido", 
    1 => "Um",
    2 => "Dois",
    _ => "Indefinido"
};

See more about improvements to Pattern matching in C# 9 in the documentation.

  • very good, as I am using the C#9, the -1 or 0 => "Invalido" was perfect

  • @Ricardopunctual Yes, the Pattern matching from C# is getting very good.

5

In this simple example you can declare a variable and use other comparison operators. As for Example:

  int num = ObterUmNumero();

  var descricao = num switch
    {
        var i when (i <= 0)  => "Inválido",
        1 => "Um",
        2 => "Dois",
        _ => "Indefinido"
    };

In case of multiple options, you can add multiple conditions as well:

int num = ObterUmNumero();

var descricao = num switch
{
    var i when (i == -1 || i == 0) => "Inválido",
    1 => "Um",
    2 => "Dois",
    _ => "Indefinido"
};

It is also interesting how it can be used for other types of treatment when using a string, as a simple comparison using contains or even more complex patterns using regex.

string mensagem = "Erro: Ocorreu uma falha no sistema";

var tipoMensagem = mensagem switch
{
    var i when (i.ToLowerInvariant().Contains("sucesso")) => "Sucesso",
    var i when (i.ToLowerInvariant().Contains("erro")) => "Erro",
    _ => "Informação"
};
  • I was in doubt in the second example: var i when (i == -1 || i == 0) => "Inválido", the switch is evaluating the variable num, if you declare the variable i, what her relationship with num? it would have the value of num?

  • even with the declaration of var i, for it will be assigned the value of num, ends up working more like a container for comparison of when. Just as we had previously in the full syntax of switch . switch (num){ case int i when (i <= 0): texto = "inválido";}

  • The explanation https://docs.microsoft.com/pt-br/dotnet/csharp/language-reference/keywords/switch#case-Labels

Browser other questions tagged

You are not signed in. Login or sign up in order to post.