C # equivalent to rust match

Rust has a convenient expression match. It works similarly switch, but there may be several variables.

Here is a pseudo example that executes fizz-buzz using this method:

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

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

+6
source share
4 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)]}");
        }
    }
}

Now you need to use the NuGet package manager to add the package ValueTupleto your project to compile the syntax. Types ValueTupleimplement appropriate equality comparisons so the dictionary can work.

+3
source

@PeterDuniho , . ( , ) # 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;
}

, , , :

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;
}

, - , . , , .

, . , , , , ( , , , ).

+1

# 7 LINQ ValueTuple:

class Program
{
    static void Main()
    {
        var fb =
            Enumerable.Range(0, 20)
            .Select(n => ((n % 3 == 0), (n % 5 == 0)))
            .Match(
                ((true, true), () => "FizzBuzz"),
                ((true, false), () => "Fizz"),
                ((false, true), () => "Buzz")
            );

        Console.WriteLine(String.Join("\n", fb));

        Console.ReadKey();
    }
}

public static class Extensions
{
    public static IEnumerable<TResult> Match<TInput, TResult>(
        this IEnumerable<TInput> e, 
        params ValueTuple<TInput, Func<TResult>>[] cases)
    {
        return
            from evalue in e
            join @case in cases on evalue equals @case.Item1
            select @case.Item2();
    }
}

, , .

Or you can return to the Paleolithic:

switch ((n % 3 == 0 ? 1 : 0) | ((n % 5 == 0) ? 2 : 0))
{
    case 1:
        //"Fizz";
        break;
    case 2:
        //"Buzz";
        break;
    case 3:
        //"FizzBuzz";
        break;
}
0
source

By adding an answer to @ErikFunkenbusch with ValueTuples, we can use this function to access elements ValueTupleby name, instead of using Item1, Item2etc.:

(bool IsDivisibleBy3, bool IsDivisibleBy5) match = (i % 3 == 0, i % 5 == 0);
switch (match)
{
    case var _ when match.IsDivisibleBy3 && match.IsDivisibleBy5:
        // FizzBuzz
        break;
    case var _ when match.IsDivisibleBy3:
        // Fizz
        break;
    case var _ when match.IsDivisibleBy5:
        // Buzz
        break;
    default:
        //
        break;
}
0
source

Source: https://habr.com/ru/post/1017140/


All Articles