C#相当于生锈"匹配"

时间:2017-05-10 15:10:01

标签: c#

在Rust中有一个名为match的便捷语句。它与switch类似,但可能有多个变量。

以下是使用此技术进行fizz-buzz的伪示例:

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

是否可以使用C#7进行相同或类似的操作?

4 个答案:

答案 0 :(得分:3)

我会在C#7中使用元组语法:

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)]}");
        }
    }
}

目前,您需要使用NuGet包管理器将ValueTuple包添加到项目中以进行编译。 ValueTuple类型实现了适当的相等比较,以允许字典工作。

答案 1 :(得分:1)

感谢@PeterDuniho指出了实现这项工作的方法。以下代码(虽然不像锈色代码那样简洁和干净)在C#7中有效。

(None,1)

您可以使用这样的逻辑快捷键来缩短上述内容:

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

这样可行,因为如果前一个参数为假,它只能评估第二个和第三个参数。当然,这只适用于像这样的简单布尔情况。

此外,我对此处的财产评估持谨慎态度,并附带副作用。你不应该设计具有副作用的属性,但如果你这样做,可能会多次评估属性,导致副作用多次应用(即,说你的属性每次增加或减少一个值&# 39; s叫。)

答案 2 :(得分:0)

在C#7中,您可以使用ValueTuple编写一个扩展方法来或多或少地使用LINQ伪造该语法:

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

我质疑任何在生产代码中这样做的人的理智,但我会在下次面试时牢记这一点。

或者你可以回到旧石器时代:

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

答案 3 :(得分:0)

使用ValueTuple添加到@ ErikFunkenbusch的{​​{3}},我们可以进一步利用此功能按名称访问ValueTuple个项目,而不是使用Item1,{{1等等:

Item2