Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# equivalent of rusts "match"

Tags:

c#

In Rust there is a handy statement called match. It works similar to switch, however there can be multiple variables.

Here is a pseudo-example doing fizz-buzz using this technique:

match (i % 3 == 0, i % 5 == 0) {
    (false, false)  =>  { // },
    (true, true)    =>  { // FizzBuzz },
    (true, false)   =>  { // Fizz },
    (false, true)   =>  { // Buzz }
}

Is it possible to do same or something similar using C# 7?

like image 926
Stan Avatar asked May 10 '17 15:05

Stan


Video Answer


2 Answers

I would use the tuple syntax in C# 7 for this:

class Program
{
    enum FizzBuzz
    {
        None,
        Fizz,
        Buzz,
        FizzBuzz
    }

    static void Main(string[] args)
    {
        // Declare the map
        Dictionary<(bool, bool), FizzBuzz> matchMap =
            new Dictionary<(bool, bool), FizzBuzz>
            {
                {  (false, false), FizzBuzz.None },
                {  (true, true), FizzBuzz.FizzBuzz },
                {  (true, false), FizzBuzz.Fizz },
                {  (false, true), FizzBuzz.Buzz },
            };

        // Demonstration of the map
        for (int i = 0; i < 16; i++)
        {
            Console.WriteLine($"i: {i}, (i % 3 == 0, i % 5 == 0): {matchMap[(i % 3 == 0, i % 5 == 0)]}");
        }
    }
}

For now, you need to use the NuGet Package Manager to add the ValueTuple package to your project for the syntax to compile. The ValueTuple types implement the appropriate equality comparison to allow the dictionary to work.

like image 102
Peter Duniho Avatar answered Sep 29 '22 18:09

Peter Duniho


Thanks to @PeterDuniho for pointing out a way to make this work. The following code (while not as succinct and clean as the rust code) works in C# 7.

switch((i % 3 == 0, i % 5 == 0))
{
case ValueTuple<bool, bool> t when (t.Item1 == true && t.Item2 == true):
// FizzBuzz    
    break;
case ValueTuple<bool, bool> t when (t.Item1 == true && t.Item2 == false):
// Fizz
    break;
case ValueTuple<bool, bool> t when (t.Item1 == false && t.Item2 == true):
// Buzz    
    break;
}

You could probably shorten the above even more by using logical shortcuts like this:

switch((i % 3 == 0, i % 5 == 0))
{
case ValueTuple<bool, bool> t when (t.Item1 && t.Item2):
// FizzBuzz    
    break;
case ValueTuple<bool, bool> t when (t.Item1):
// Fizz
    break;
case ValueTuple<bool, bool> t when (t.Item2):
// Buzz    
    break;
}

This would work because it would only ever get to evaluate the second and third arguments if the previous one was false. Of course this only really works in a simple Boolean situation like this.

Also, i'd be wary about property evaluation here with side-effects. You shouldn't design properties to have side-effects, but if you do this might evaluate the properties multiple times, causing the side-effects to applied multiple times (ie, say your property adds or decrements a value each time it's called).

like image 35
Erik Funkenbusch Avatar answered Sep 29 '22 17:09

Erik Funkenbusch