C#中的内联switch/case语句

26

我正在尝试通过让代码行数尽可能少来实现某个奇怪的目标。有没有一种方法可以将这段代码压缩为内联案例语句?

    switch (FIZZBUZZ)
    {
      case "Fizz":
        {
          //Do one process
          break;
        }
      case "Buzz":
        {
          //Do one process
          break;
        }
      case "FizzBuzz":
        {
          //Do one process
          break;
        }
    }

看起来应该像这样:

    switch (FIZZBUZZ)
    {
      case "Fizz": //Do one process
      case "Buzz": //Do one process
      case "FizzBuzz": //Do one process
    }

8
别太过追求技巧,有些事情可以这样做得很好,但通常你会写出越来越难读的代码。请放弃这种做法。 - Jimmy Hoffa
3
我认为这需要更新,因为在C# 8中是有可能的。 - Ben
13个回答

89

在C# 8中引入。

现在您可以这样执行switch操作:

FIZZBUZZ switch
{
    "fizz"     => /*do something*/,
    "fuzz"     => /*do something*/,
    "FizzBuzz" => /*do something*/,
    _ => throw new Exception("Oh ooh")
};

可以这样完成赋值:

string FIZZBUZZ = "fizz";
string result = FIZZBUZZ switch
    {
        "fizz"     => "this is fizz",
        "fuzz"     => "this is fuzz",
        "FizzBuzz" => "this is FizzBuzz",
        _ => throw new Exception("Oh ooh")
    };
Console.WriteLine($"{ result }"); // this is fizz

函数调用:

public string Fizzer()     => "this is fizz";
public string Fuzzer()     => "this is fuzz";
public string FizzBuzzer() => "this is FizzBuzz";
...
string FIZZBUZZ = "fizz";

string result = FIZZBUZZ switch
    {
        "fizz"     => Fizzer(),
        "fuzz"     => Fuzzer(),
        "FizzBuzz" => FizzBuzzer(),
        _ => throw new Exception("Oh ooh")
    };
Console.WriteLine($"{ result }"); // this is fizz

每个案例可以有多个内联操作(我认为委托是必须的):

string FIZZBUZZ = "fizz";
string result = String.Empty;

_= (FIZZBUZZ switch
{
    "fizz" => () =>
    {
        Console.WriteLine("fizz");
        result = "fizz";
    },
    "fuzz" => () =>
    {
        Console.WriteLine("fuzz");
        result = "fuzz";
    },
    _ => new Action(() => { })
});

您可以在此处阅读有关新的switch case的更多信息:C# 8.0 的新增内容


独立丢弃(standalone discard)(https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards#a-standalone-discard),这正是我所需要的,谢谢。 - Lak Fu
因为我想在属性(set)中使用条件运算符,但返回值会导致语法错误。你的第四行展示了独立的丢弃(_ = ....),它可以解决我的问题。所以,谢谢。XD - Lak Fu

27
如果您想压缩代码,您可以将代码放在一行上(假设“执行一个进程”是对Console.WriteLine的调用):
switch (FIZZBUZZ)
{
    case "Fizz": Console.WriteLine("Fizz"); break;
    case "Buzz": Console.WriteLine("Buzz"); break;
    case "FizzBuzz": Console.WriteLine("FizzBuzz"); break;
}

如果你想变得花哨些,你可以创建一个字符串和操作之间的映射表,就像这样:

var map = new Dictionary<String, Action>
{
    { "Fizz", () => Console.WriteLine("Fizz") },
    { "Buzz", () => Console.WriteLine("Fizz") },
    { "FizzBuzz", () => Console.WriteLine("FizzBuzz") }
};

然后你可以像这样调用该方法:

map[FIZZBUZZ].Invoke(); // or this: map[FIZZBUZZ]();

我有“handleFizz”和“handleBuzz”来处理两个调用,然后为fizzbuzz同时调用它们。这样做会重复代码。尽管我喜欢简洁,但我更喜欢效率。 :) - Jim
1
@Jim - 我喜欢正确性、可读性和可维护性。至少在fizzbuzz的例子中,我们的兴趣可能是一致的。:-) - Jeffrey L Whitledge

16

顺便提一下,如果有人正在寻找一种行内简写的switch case语句来返回值,我发现对我来说最好的解决方案是多次使用三元操作符:

string Season = "Spring";
Season = Season == "Fall" ? "Spring" : Season == "Spring" ? "Summer" : "Fall";

你可以选择将其放在括号中,使它更易读但仍然是内联的:

Season = (Season == "Fall" ? "Spring" : (Season == "Spring" ? "Summer" : "Fall"));

或者使用多行并缩进它:

Season = Season == "Fall" ? "Spring" 
       : Season == "Spring" ? "Summer" 
       : "Fall";

因此,要用作代码执行块,您可以编写:

string FizzBuzz = "Fizz";
FizzBuzz = FizzBuzz == "Fizz" ? MethodThatReturnsAString("Fizz") : (FizzBuzz == "Buzz" ? MethodThatReturnsAString("Buzz") : MethodThatReturnsAString("FizzBuzz"));

虽然这不是处理大量case元素的最佳解决方案,但您正在尝试使用内联switch语句 ;)

社区对此有何评价?


这种方法和使用“外部”循环相比,性能如何? - Juan Ruiz de Castilla

9

假设这仅仅是一种玄学的方法,并且您不会考虑在生产系统中使用它,那么您可以滥用表达式树:

FIZZBUZZ.Switch(Fizz => DoSomething(),
                Buzz => DoSomethingElse(),
                FizzBuzz => DoSomethingElseStill());

这里的Switch是一个扩展方法:

public static void Switch(this string @this, params Expression<Action>[] cases)
{
    Expression<Action> matchingAction = cases.SingleOrDefault(@case => @case.Parameters[0].Name == @this);
    if (matchingAction == null) return; // no matching action

    matchingAction.Compile()();
}

1
我喜欢它!做事情的方式很有趣。 - Jeremy Holovacs

6
在C# 8中,你可以像这样做:
    public Form1()
    {
        InitializeComponent();
        Console.WriteLine(GetSomeString("Fizz"));
    }

    public static string GetSomeString(string FIZZBUZZ) =>
       FIZZBUZZ switch
       {
           "Fizz" => "this is Fizz",
           "Buzz" => "this is Buzz",
           "FizzBuzz" => "this is FizzBuzz",
           _ => "Unknown"
       };

这相当于
    public static string GetSomeString(string FIZZBUZZ)
    {
        switch (FIZZBUZZ)
        {
            case "Fizz": return "this is Fizz";
            case "Buzz": return "this is Buzz";
            case "FizzBuzz": return "this is FizzBuzz";
            default: return "Unknown";
        }
    }

是的,但你正在返回一个值。挑战在于执行一个动作。 - Andrew Shepherd

1

在离开switch之前,您总是需要有一个break语句,除此之外,您可以按照您提到的方式进行操作。

  switch (FIZZBUZZ)
    {
      case "Fizz": /*Do one process*/break;
      case "Buzz": /*Do one process*/break;
      case "FizzBuzz": /*Do one process*/break;
    }

1

如果您真的对代码行数最少感兴趣,您可以这样写:

switch (FIZZBUZZ) { case "Fizz": /* Do one process */ break; case "Buzz": /* Do one process */ break; case "FizzBuzz": /* Do one process */ break; }

虽然我不建议这样做。

不过很难确切地知道你在问什么——你是想要在 case 之间执行下一个 case,还是只是想要删除大括号?


2
我曾经对一个激怒我的同事这样做过。把整个类都写在一行里。 - Joel Etherton
我正在尝试去掉大括号。 - Jim
@Jim: 除了switch块本身周围的花括号,你其实不需要其他的花括号,所以可以直接移除。不过,如果在这些情况下创建变量,建议保留花括号以确保作用域的安全性。 - Jimmy Hoffa

0

所以我把这个当作一个挑战。与其给出“只需使用Switch..Case语法”的常规答案,我将其视为技能和知识的编码挑战(尽管我两者都不太擅长)。

设置

使用

public enum FizzBuzz {
    Fizz,
    Buzz,
    FizzBuzz
}

public static class EnumExtension {
    public static void SwitchCase ( this FizzBuzz enm , params KeyValuePair<FizzBuzz , Action> [] parms ) {
        foreach ( var kvp in parms ) {
            if ( kvp.Key == enm ) {
                kvp.Value();
            }
        }
    }
}

实现

public class Program {
    static void Main ( string [] args ) {
        var enm = FizzBuzz.Fizz;

        ProcessEnum( enm );
    }

    public static void ProcessEnum ( FizzBuzz enm ) {
        enm.SwitchCase(
            new KeyValuePair<FizzBuzz , Action>( FizzBuzz.Fizz , FizzMethod ) ,
            new KeyValuePair<FizzBuzz , Action>( FizzBuzz.Buzz , BuzzMethod ) ,
            new KeyValuePair<FizzBuzz , Action>( FizzBuzz.FizzBuzz , FizzBuzzMethod )
            );
    }

    private static void FizzMethod () {
        System.Console.WriteLine( "" );
    }
    private static void BuzzMethod () {
        System.Console.WriteLine( "" );
    }
    private static void FizzBuzzMethod () {
        System.Console.WriteLine( "" );
    }

}

0

一个简单的方法是:

switch (FIZZBUZZ)
{
     case "Fizz": Console.WriteLine("Fizz"); break;
     case "Buzz": Console.WriteLine("Buzz"); break;
     case "FizzBuzz": Console.WriteLine("FizzBuzz"); break;
}

每行只有一条语句,但每行可能包含多个语句...


0

我不知道有什么方法可以保持一定的可读性,除了显而易见的方法:

switch (FIZZBUZZ) 
    { 
      case "Fizz": { //Do one process } break;
      case "Buzz": { //Do one process  } break;
      case "FizzBuzz": { //Do one process  } break;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接