简体   繁体   中英

Inline switch / case statement in C#

I am on a weird kick of seeing how few lines I can make my code. Is there a way to condense this to inline case statements?

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

to look something like this:

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

Introduced in C# 8.

You can now do switch operations like this:

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

Assignment can be done like this:

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

Function calls:

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

Multiple inline-actions per case ( delegates are a must I think ):

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

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

You can read more about the new switch case here: What's new in C# 8.0

If you want to condense things you could just put things on one line (let's imagine that "do one process is a call to Console.WriteLine ):

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

If you want to get fancy you could create a map of strings to actions like this:

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

And then you could invoke the method like this:

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

FYI, if anyone was looking for a inline shorthand switch case statement to return a value, I found the best solution for me was to use the ternary operator multiple times:

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

You can optionally make it more readable while still inline by wrapping it in parens:

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

or by using multiple lines and indenting it:

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

So, to serve as a code execution block you could write:

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

Not the most respectable solution for a long list of case elements, but you are trying to do an inline switch statement ;)

Critiques from the community?

With the assumption that this is purely esoteric and that you will not be tempted to use this in a production system, you could abuse expression trees:

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

Where Switch is an extension method:

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

In C# 8 you can do something like this

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

This is equivalent to

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

You always have to have a break statement in order to leave the switch other than that you can do it as you mention

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

Well if you're really interested in fewest lines of code you can write:

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

I wouldn't recommend it though.

It's hard to tell exactly what you're asking though - are you trying to fall through between cases, or just remove braces?

Well an easy way would be:

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

Which is only one line each. But there's multiple statements per line...

I don't know of any way to do this, while maintaining some readability, other than the obvious:

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

You can put as much code on one line as you like with C#.

As Andrew says.

Personally my preference is to leave white space as it allows easier reading of the code but then again I am the only dev here who comments his code or writes methods and functions small enough to be able to quickly scan the code to see exactly what it does. :)

You don't need the curly braces for the case statements, but do you need a break statement for each case. Otherwise, you can't really do much

Necromancer poster here

So I took this on as a challenge. Instead of the usual answers of "Just use Switch..Case syntax" statements, I made it a coding challenge of skill and knowledge (not that I have much of either).

Setup

Using

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

Implementation

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

}

A challenge is to use C#8 switch expressions

The problem is that the body of each branch is an expression, not a group of statements.

You can work around this by making each branch return an Action object.

Note the syntax: if I explicitly cast any one of the expressions to the Action type, then the compiler will implicitly cast each of the other expressions. I chose to cast the last (default) expression.

public static void Performction(string input) =>
    (
        (input) switch 
        {   
            "FIZZ" => () => Console.WriteLine("This is the fizz"),
            "BUZZ" => () => Console.WriteLine("This is the buzz"),
            "FIZZBUZZ" => () => 
                {
                    Console.WriteLine("This is a Fizz");
                    Console.WriteLine("But it is a buzz as well!");
                },
            _ => new Action(() => {})
        }
    )();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM